home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / MAME / src / cheat.c < prev    next >
C/C++ Source or Header  |  2000-05-13  |  77KB  |  2,823 lines

  1. /*********************************************************************
  2.  
  3.   cheat.c
  4.  
  5.   This is a massively rewritten version of the cheat engine. There
  6.   are still quite a few features that are broken or not reimplemented.
  7.  
  8.   Busted (probably permanently) is the ability to use the UI_CONFIGURE
  9.   key to pop the menu system on and off while retaining the current
  10.   menu selection. The sheer number of submenus involved makes this
  11.   a difficult task to pull off here.
  12.  
  13.   TODO:
  14.  
  15.   * comment cheats
  16.   * memory searches
  17.   * saving of cheats to a file
  18.   * inserting/deleting new cheats
  19.   * cheats as watchpoints
  20.   * key shortcuts to the search menus
  21.  
  22. (Description from Pugsy's cheat.dat)
  23.  
  24. ; all fields are separated by a colon (:)
  25. ;  -Name of the game (short name) [zip file or directory]
  26. ;  -No of the CPU usually 0, only different in multiple CPU games
  27. ;  -Address in Hexadecimal (where to poke)
  28. ;  -Data to put at this address in hexadecimal (what to poke)
  29. ;  -Special (see below) usually 000
  30. ;   -000 : the byte is poked every time and the cheat remains in active list.
  31. ;   -001 : the byte is poked once and the cheat is removed from active list.
  32. ;   -002 : the byte is poked every one second and the cheat remains in active
  33. ;          list.
  34. ;   -003 : the byte is poked every two seconds and the cheat remains in active
  35. ;          list.
  36. ;   -004 : the byte is poked every five seconds and the cheat remains in active
  37. ;          list.
  38. ;   -005 : the byte is poked one second after the original value has changed
  39. ;          and the cheat remains in active list.
  40. ;   -006 : the byte is poked two seconds after the original value has changed
  41. ;          and the cheat remains in active list.
  42. ;   -007 : the byte is poked five seconds after the original value has changed
  43. ;          and the cheat remains in active list.
  44. ;   -008 : the byte is poked unless the original value in being decremented by
  45. ;          1 each frame and the cheat remains in active list.
  46. ;   -009 : the byte is poked unless the original value in being decremented by
  47. ;          2 each frame and the cheat remains in active list.
  48. ;   -010 : the byte is poked unless the original value in being decremented by
  49. ;          3 each frame and the cheat remains in active list.
  50. ;   -011 : the byte is poked unless the original value in being decremented by
  51. ;          4 each frame and the cheat remains in active list.
  52. ;   -020 : the bits are set every time and the cheat remains in active list.
  53. ;   -021 : the bits are set once and the cheat is removed from active list.
  54. ;   -040 : the bits are reset every time and the cheat remains in active list.
  55. ;   -041 : the bits are reset once and the cheat is removed from active list.
  56. ;   -060 : the user selects a decimal value from 0 to byte
  57. ;          (display : 0 to byte) - the value is poked once when it changes and
  58. ;          the cheat is removed from the active list.
  59. ;   -061 : the user selects a decimal value from 0 to byte
  60. ;          (display : 1 to byte+1) - the value is poked once when it changes
  61. ;          and the cheat is removed from the active list.
  62. ;   -062 : the user selects a decimal value from 1 to byte
  63. ;          (display : 1 to byte) - the value is poked once when it changes and
  64. ;          the cheat is removed from the active list.
  65. ;   -063 : the user selects a BCD value from 0 to byte
  66. ;          (display : 0 to byte) - the value is poked once when it changes and
  67. ;          the cheat is removed from the active list.
  68. ;   -064 : the user selects a BCD value from 0 to byte
  69. ;          (display : 1 to byte+1) - the value is poked once when it changes
  70. ;          and the cheat is removed from the active list.
  71. ;   -065 : the user selects a decimal value from 1 to byte
  72. ;          (display : 1 to byte) - the value is poked once when it changes and
  73. ;          the cheat is removed from the active list.
  74. ;   -070 : the user selects a decimal value from 0 to byte
  75. ;          (display : 0 to byte) - the value is poked once and the cheat is
  76. ;          removed from the active list.
  77. ;   -071 : the user selects a decimal value from 0 to byte
  78. ;          (display : 1 to byte+1) - the value is poked once and the cheat is
  79. ;          removed from the active list.
  80. ;   -072 : the user selects a decimal value from 1 to byte
  81. ;          (display : 1 to byte) - the value is poked once and the cheat is
  82. ;          removed from the active list.
  83. ;   -073 : the user selects a BCD value from 0 to byte
  84. ;          (display : 0 to byte) - the value is poked once and the cheat is
  85. ;          removed from the active list.
  86. ;   -074 : the user selects a BCD value from 0 to byte
  87. ;          (display : 1 to byte+1) - the value is poked once and the cheat is
  88. ;          removed from the active list.
  89. ;   -075 : the user selects a decimal value from 1 to byte
  90. ;          (display : 1 to byte) - the value is poked once and the cheat is
  91. ;          removed from the active list.
  92. ;   -500 to 575: These cheat types are identical to types 000 to 075 except
  93. ;                they are used in linked cheats (i.e. of 1/8 type). The first
  94. ;                cheat in the link list will be the normal type (eg type 000)
  95. ;                and the remaining cheats (eg 2/8...8/8) will be of this type
  96. ;                (eg type 500).
  97. ;   -998 : this is used as a watch cheat, ideal for showing answers in quiz
  98. ;          games .
  99. ;   -999 : this is used for comments only, cannot be enabled/selected by the
  100. ;          user.
  101. ;  -Name of the cheat
  102. ;  -Description for the cheat
  103.  
  104. *********************************************************************/
  105.  
  106. #include "driver.h"
  107. #include "ui_text.h"
  108.  
  109. #ifndef NEOFREE
  110. #ifndef TINY_COMPILE
  111. extern struct GameDriver driver_neogeo;
  112. #endif
  113. #endif
  114.  
  115. extern unsigned char *memory_find_base (int cpu, int offset);
  116.  
  117. /*****************
  118.  *
  119.  * Cheats
  120.  *
  121.  */
  122. #define SUBCHEAT_FLAG_DONE        0x0001
  123. #define SUBCHEAT_FLAG_TIMED        0x0002
  124.  
  125. struct subcheat_struct
  126. {
  127.     int cpu;
  128.     offs_t address;
  129.     data_t data;
  130.     data_t backup;                        /* The original value of the memory location, checked against the current */
  131.     UINT32 code;
  132.     UINT16 flags;
  133.     data_t min;
  134.     data_t max;
  135.     UINT32 frames_til_trigger;            /* the number of frames until this cheat fires (does not change) */
  136.     UINT32 frame_count;                    /* decrementing frame counter to determine if cheat should fire */
  137. };
  138.  
  139. #define CHEAT_FLAG_ACTIVE    0x01
  140. #define CHEAT_FLAG_WATCH    0x02
  141. #define CHEAT_FLAG_COMMENT    0x04
  142.  
  143. struct cheat_struct
  144. {
  145.     char *name;
  146.     char *comment;
  147.     UINT8 flags;                        /* bit 0 = active, 1 = watchpoint, 2 = comment */
  148.     int num_sub;                        /* number of cheat cpu/address/data/code combos for this one cheat */
  149.     struct subcheat_struct *subcheat;    /* a variable-number of subcheats are attached to each "master" cheat */
  150. };
  151.  
  152. struct memory_struct
  153. {
  154.     int Enabled;
  155.     char name[40];
  156.     mem_write_handler handler;
  157. };
  158.  
  159. enum
  160. {
  161.     kCheatSpecial_Poke = 0,
  162.     kCheatSpecial_Poke1 = 2,
  163.     kCheatSpecial_Poke2 = 3,
  164.     kCheatSpecial_Poke5 = 4,
  165.     kCheatSpecial_Delay1 = 5,
  166.     kCheatSpecial_Delay2 = 6,
  167.     kCheatSpecial_Delay5 = 7,
  168.     kCheatSpecial_Backup1 = 8,
  169.     kCheatSpecial_Backup4 = 11,
  170.     kCheatSpecial_SetBit1 = 22,
  171.     kCheatSpecial_SetBit2 = 23,
  172.     kCheatSpecial_SetBit5 = 24,
  173.     kCheatSpecial_ResetBit1 = 42,
  174.     kCheatSpecial_ResetBit2 = 43,
  175.     kCheatSpecial_ResetBit5 = 44,
  176.     kCheatSpecial_UserFirst = 60,
  177.     kCheatSpecial_m0d0c = 60,            /* minimum value 0, display range 0 to byte, poke when changed */
  178.     kCheatSpecial_m0d1c = 61,            /* minimum value 0, display range 1 to byte+1, poke when changed */
  179.     kCheatSpecial_m1d1c = 62,            /* minimum value 1, display range 1 to byte, poke when changed */
  180.     kCheatSpecial_m0d0bcdc = 63,        /* BCD, minimum value 0, display range 0 to byte, poke when changed */
  181.     kCheatSpecial_m0d1bcdc = 64,        /* BCD, minimum value 0, display range 1 to byte+1, poke when changed */
  182.     kCheatSpecial_m1d1bcdc = 65,        /* BCD, minimum value 1, display range 1 to byte, poke when changed */
  183.     kCheatSpecial_m0d0 = 70,            /* minimum value 0, display range 0 to byte */
  184.     kCheatSpecial_m0d1 = 71,            /* minimum value 0, display range 1 to byte+1 */
  185.     kCheatSpecial_m1d1 = 72,            /* minimum value 1, display range 1 to byte */
  186.     kCheatSpecial_m0d0bcd = 73,            /* BCD, minimum value 0, display range 0 to byte */
  187.     kCheatSpecial_m0d1bcd = 74,            /* BCD, minimum value 0, display range 1 to byte+1 */
  188.     kCheatSpecial_m1d1bcd = 75,            /* BCD, minimum value 1, display range 1 to byte */
  189.     kCheatSpecial_UserLast = 75,
  190.     kCheatSpecial_Last = 99,
  191.     kCheatSpecial_LinkStart = 500,        /* only used when loading the database */
  192.     kCheatSpecial_LinkEnd = 599,        /* only used when loading the database */
  193.     kCheatSpecial_Watch = 998,
  194.     kCheatSpecial_Comment = 999,
  195.     kCheatSpecial_Timed = 1000
  196. };
  197.  
  198. /*****************
  199.  *
  200.  * Watchpoints
  201.  *
  202.  */
  203. #define MAX_WATCHES     20
  204.  
  205. struct watch_struct
  206. {
  207.     int cheat_num;        /* if this watchpoint is tied to a cheat, this is the index into the cheat array. -1 if none */
  208.     UINT32 address;
  209.     INT16 cpu;
  210.     UINT8 num_bytes;    /* number of consecutive bytes to display */
  211.     UINT8 label_type;    /* none, address, text */
  212.     char label[255];    /* optional text label */
  213.     UINT16 x, y;        /* position of watchpoint on screen */
  214. };
  215.  
  216. static struct watch_struct watches[MAX_WATCHES];
  217. static int is_watch_active; /* true if at least one watchpoint is active */
  218. static int is_watch_visible; /* we can toggle the visibility for all on or off */
  219.  
  220. /* in hiscore.c */
  221. int computer_readmem_byte(int cpu, int addr);
  222. void computer_writemem_byte(int cpu, int addr, int value);
  223.  
  224. /* Some macros to simplify the code */
  225. #define READ_CHEAT                computer_readmem_byte (subcheat->cpu, subcheat->address)
  226. #define WRITE_CHEAT                computer_writemem_byte (subcheat->cpu, subcheat->address, subcheat->data)
  227. #define COMPARE_CHEAT            (computer_readmem_byte (subcheat->cpu, subcheat->address) != subcheat->data)
  228. #define CPU_AUDIO_OFF(index)    ((Machine->drv->cpu[index].cpu_type & CPU_AUDIO_CPU) && (Machine->sample_rate == 0))
  229.  
  230. #define MAX_LOADEDCHEATS    200
  231. #define CHEAT_FILENAME_MAXLEN    255
  232.  
  233. /* This variables are not static because of extern statement */
  234. char *cheatfile = "cheat.dat";
  235. char database[CHEAT_FILENAME_MAXLEN+1];
  236.  
  237. int he_did_cheat;
  238.  
  239. //int fastsearch = 2;
  240. //int sologame   = 0;
  241.  
  242. /* Local routines */
  243. static INT32 DisplayHelpFile (INT32 selected);
  244. static INT32 EditCheatMenu (struct osd_bitmap *bitmap, INT32 selected, UINT8 cheatnum);
  245. static INT32 CommentMenu (struct osd_bitmap *bitmap, INT32 selected, int cheat_index);
  246.  
  247. /* Local variables */
  248. /* static int    search_started = 0; */
  249.  
  250. #if 0
  251. static struct ExtMemory StartRam[MAX_EXT_MEMORY];
  252. static struct ExtMemory BackupRam[MAX_EXT_MEMORY];
  253. static struct ExtMemory FlagTable[MAX_EXT_MEMORY];
  254.  
  255. static struct ExtMemory OldBackupRam[MAX_EXT_MEMORY];
  256. static struct ExtMemory OldFlagTable[MAX_EXT_MEMORY];
  257. #endif
  258.  
  259. static int ActiveCheatTotal;                                        /* number of cheats currently active */
  260. static int LoadedCheatTotal;                                        /* total number of cheats */
  261. static struct cheat_struct CheatTable[MAX_LOADEDCHEATS+1];
  262.  
  263. static int CheatEnabled;
  264.  
  265. /* Function to test if a value is BCD (returns 1) or not (returns 0) */
  266. int IsBCD(int ParamValue)
  267. {
  268.     return(((ParamValue % 0x10 <= 9) & (ParamValue <= 0x99)) ? 1 : 0);
  269. }
  270.  
  271. #if 0
  272. /* return a format specifier for printf based on cpu address range */
  273. static char *FormatAddr(int cpu, int addtext)
  274. {
  275.     static char bufadr[10];
  276.     static char buffer[18];
  277.     int i;
  278.  
  279.     memset (buffer, '\0', strlen(buffer));
  280.     switch (cpunum_address_bits(cpu) >> 2)
  281.     {
  282.         case 4:
  283.             strcpy (bufadr, "%04X");
  284.             break;
  285.         case 5:
  286.             strcpy (bufadr, "%05X");
  287.             break;
  288.         case 6:
  289.             strcpy (bufadr, "%06X");
  290.             break;
  291.         case 7:
  292.             strcpy (bufadr, "%07X");
  293.             break;
  294.         case 8:
  295.             strcpy (bufadr, "%08X");
  296.             break;
  297.         default:
  298.             strcpy (bufadr, "%X");
  299.             break;
  300.     }
  301.       if (addtext)
  302.       {
  303.     strcpy (buffer, "Addr:  ");
  304.         for (i = strlen(bufadr) + 1; i < 8; i ++)
  305.         strcat (buffer, " ");
  306.       }
  307.       strcat (buffer,bufadr);
  308.     return buffer;
  309. }
  310. #endif
  311.  
  312. #if 0
  313. /* make a copy of a source ram table to a dest. ram table */
  314. static void copy_ram (struct ExtMemory *dest, struct ExtMemory *src)
  315. {
  316.     struct ExtMemory *ext_dest, *ext_src;
  317.  
  318.     for (ext_src = src, ext_dest = dest; ext_src->data; ext_src++, ext_dest++)
  319.     {
  320.         memcpy (ext_dest->data, ext_src->data, ext_src->end - ext_src->start + 1);
  321.     }
  322. }
  323.  
  324. /* make a copy of each ram area from search CPU ram to the specified table */
  325. static void backup_ram (struct ExtMemory *table)
  326. {
  327.     struct ExtMemory *ext;
  328.     unsigned char *gameram;
  329.  
  330.     for (ext = table; ext->data; ext++)
  331.     {
  332.         int i;
  333.         gameram = memory_find_base (Searchcpu, ext->start);
  334.         memcpy (ext->data, gameram, ext->end - ext->start + 1);
  335.         for (i=0; i <= ext->end - ext->start; i++)
  336.             ext->data[i] = computer_readmem_byte(Searchcpu, i+ext->start);
  337.     }
  338. }
  339.  
  340. /* set every byte in specified table to data */
  341. static void memset_ram (struct ExtMemory *table, unsigned char data)
  342. {
  343.     struct ExtMemory *ext;
  344.  
  345.     for (ext = table; ext->data; ext++)
  346.         memset (ext->data, data, ext->end - ext->start + 1);
  347. }
  348.  
  349. /* free all the memory and init the table */
  350. static void reset_table (struct ExtMemory *table)
  351. {
  352.     struct ExtMemory *ext;
  353.  
  354.     for (ext = table; ext->data; ext++)
  355.         free (ext->data);
  356.     memset (table, 0, sizeof (struct ExtMemory) * MAX_EXT_MEMORY);
  357. }
  358.  
  359. /* Returns 1 if memory area has to be skipped */
  360. int SkipBank(int CpuToScan, int *BankToScanTable, mem_write_handler handler)
  361. {
  362.     int res = 0;
  363.  
  364.     if ((fastsearch == 1) || (fastsearch == 2))
  365.     {
  366.         switch ((FPTR)handler)
  367.         {
  368.             case (FPTR)MWA_RAM:
  369.                 res = !BankToScanTable[0];
  370.                 break;
  371.             case (FPTR)MWA_BANK1:
  372.                 res = !BankToScanTable[1];
  373.                 break;
  374.             case (FPTR)MWA_BANK2:
  375.                 res = !BankToScanTable[2];
  376.                 break;
  377.             case (FPTR)MWA_BANK3:
  378.                 res = !BankToScanTable[3];
  379.                 break;
  380.             case (FPTR)MWA_BANK4:
  381.                 res = !BankToScanTable[4];
  382.                 break;
  383.             case (FPTR)MWA_BANK5:
  384.                 res = !BankToScanTable[5];
  385.                 break;
  386.             case (FPTR)MWA_BANK6:
  387.                 res = !BankToScanTable[6];
  388.                 break;
  389.             case (FPTR)MWA_BANK7:
  390.                 res = !BankToScanTable[7];
  391.                 break;
  392.             case (FPTR)MWA_BANK8:
  393.                 res = !BankToScanTable[8];
  394.                 break;
  395.             default:
  396.                 res = 1;
  397.                 break;
  398.         }
  399.     }
  400.     return(res);
  401. }
  402. #endif
  403.  
  404. /* Function to rename the cheatfile (returns 1 if the file has been renamed else 0)*/
  405. int RenameCheatFile(int merge, int DisplayFileName, char *filename)
  406. {
  407.     return 0;
  408. }
  409.  
  410. /* Function who loads the cheats for a game */
  411. int SaveCheat(int NoCheat)
  412. {
  413.     return 0;
  414. }
  415.  
  416. /***************************************************************************
  417.  
  418.   cheat_set_code
  419.  
  420.   Given a cheat code, sets the various attribues of the cheat structure.
  421.   This is to aid in making the cheat engine more flexible in the event that
  422.   someday the codes are restructured or the case statement in DoCheat is
  423.   simplified from its current form.
  424.  
  425. ***************************************************************************/
  426. void cheat_set_code (struct subcheat_struct *subcheat, int code, int cheat_num)
  427. {
  428.     switch (code)
  429.     {
  430.         case kCheatSpecial_Poke1:
  431.         case kCheatSpecial_Delay1:
  432.         case kCheatSpecial_SetBit1:
  433.         case kCheatSpecial_ResetBit1:
  434.             subcheat->frames_til_trigger = 1 * Machine->drv->frames_per_second; /* was 60 */
  435.             break;
  436.         case kCheatSpecial_Poke2:
  437.         case kCheatSpecial_Delay2:
  438.         case kCheatSpecial_SetBit2:
  439.         case kCheatSpecial_ResetBit2:
  440.             subcheat->frames_til_trigger = 2 * Machine->drv->frames_per_second; /* was 60 */
  441.             break;
  442.         case kCheatSpecial_Poke5:
  443.         case kCheatSpecial_Delay5:
  444.         case kCheatSpecial_SetBit5:
  445.         case kCheatSpecial_ResetBit5:
  446.             subcheat->frames_til_trigger = 5 * Machine->drv->frames_per_second; /* was 60 */
  447.             break;
  448.         case kCheatSpecial_Comment:
  449.             subcheat->frames_til_trigger = 0;
  450.             subcheat->address = 0;
  451.             subcheat->data = 0;
  452.             CheatTable[cheat_num].flags |= CHEAT_FLAG_COMMENT;
  453.             break;
  454.         case kCheatSpecial_Watch:
  455.             subcheat->frames_til_trigger = 0;
  456.             subcheat->data = 0;
  457.             CheatTable[cheat_num].flags |= CHEAT_FLAG_WATCH;
  458.             break;
  459.         default:
  460.             subcheat->frames_til_trigger = 0;
  461.             break;
  462.     }
  463.  
  464.     /* Set the minimum value */
  465.     if ((code == kCheatSpecial_m1d1c) ||
  466.         (code == kCheatSpecial_m1d1bcdc) ||
  467.         (code == kCheatSpecial_m1d1) ||
  468.         (code == kCheatSpecial_m1d1bcd))
  469.         subcheat->min = 1;
  470.     else
  471.         subcheat->min = 0;
  472.  
  473.     /* Set the maximum value */
  474.     if ((code >= kCheatSpecial_UserFirst) &&
  475.         (code <= kCheatSpecial_UserLast))
  476.     {
  477.         subcheat->max = subcheat->data;
  478.         subcheat->data = 0;
  479.     }
  480.     else
  481.         subcheat->max = 0xff;
  482.  
  483.     subcheat->code = code;
  484. }
  485.  
  486. /***************************************************************************
  487.  
  488.   cheat_set_status
  489.  
  490.   Given an index into the cheat table array, make the selected cheat
  491.   either active or inactive.
  492.  
  493.   TODO: possibly support converting to a watchpoint in here.
  494.  
  495. ***************************************************************************/
  496. void cheat_set_status (int cheat_num, int active)
  497. {
  498.     int i;
  499.  
  500.     if (active) /* enable the cheat */
  501.     {
  502.         for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
  503.         {
  504.             /* Reset the active variables */
  505.             CheatTable[cheat_num].subcheat[i].frame_count = 0;
  506.             CheatTable[cheat_num].subcheat[i].backup = 0;
  507.         }
  508.  
  509.         /* only add if there's a cheat active already */
  510.         if ((CheatTable[cheat_num].flags & CHEAT_FLAG_ACTIVE) == 0)
  511.         {
  512.             CheatTable[cheat_num].flags |= CHEAT_FLAG_ACTIVE;
  513.             ActiveCheatTotal++;
  514.         }
  515.  
  516.         /* tell the MAME core that we're cheaters! */
  517.         he_did_cheat = 1;
  518.     }
  519.     else /* disable the cheat (case 0, 2) */
  520.     {
  521.         for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
  522.         {
  523.             /* Reset the active variables */
  524.             CheatTable[cheat_num].subcheat[i].frame_count = 0;
  525.             CheatTable[cheat_num].subcheat[i].backup = 0;
  526.         }
  527.  
  528.         /* only add if there's a cheat active already */
  529.         if (CheatTable[cheat_num].flags & CHEAT_FLAG_ACTIVE)
  530.         {
  531.             CheatTable[cheat_num].flags &= ~CHEAT_FLAG_ACTIVE;
  532.             ActiveCheatTotal--;
  533.         }
  534.     }
  535. }
  536.  
  537. void cheat_insert_new (int cheat_num)
  538. {
  539.     /* if list is full, bail */
  540.     if (LoadedCheatTotal == MAX_LOADEDCHEATS) return;
  541.  
  542.     /* if the index is off the end of the list, fix it */
  543.     if (cheat_num > LoadedCheatTotal) cheat_num = LoadedCheatTotal;
  544.  
  545.     /* clear space in the middle of the table if needed */
  546.     if (cheat_num < LoadedCheatTotal)
  547.         memmove (&CheatTable[cheat_num+1], &CheatTable[cheat_num], sizeof (struct cheat_struct) * (LoadedCheatTotal - cheat_num));
  548.  
  549.     /* clear the new entry */
  550.     memset (&CheatTable[cheat_num], 0, sizeof (struct cheat_struct));
  551.  
  552.     CheatTable[cheat_num].name = malloc (strlen (ui_getstring(UI_none)) + 1);
  553.     strcpy (CheatTable[cheat_num].name, ui_getstring(UI_none));
  554.  
  555.     CheatTable[cheat_num].subcheat = calloc (1, sizeof (struct subcheat_struct));
  556.  
  557.     /*add one to the total */
  558.     LoadedCheatTotal ++;
  559. }
  560.  
  561. void cheat_delete (int cheat_num)
  562. {
  563.     /* if the index is off the end, make it the last one */
  564.     if (cheat_num >= LoadedCheatTotal) cheat_num = LoadedCheatTotal - 1;
  565.  
  566.     /* deallocate storage for the cheat */
  567.     free (CheatTable[cheat_num].name);
  568.     free (CheatTable[cheat_num].comment);
  569.     free (CheatTable[cheat_num].subcheat);
  570.  
  571.     /* If it's active, decrease the count */
  572.     if (CheatTable[cheat_num].flags & CHEAT_FLAG_ACTIVE)
  573.         ActiveCheatTotal --;
  574.  
  575.     /* move all the elements after this one up one slot if there are more than 1 and it's not the last */
  576.     if ((LoadedCheatTotal > 1) && (cheat_num < LoadedCheatTotal - 1))
  577.         memmove (&CheatTable[cheat_num], &CheatTable[cheat_num+1], sizeof (struct cheat_struct) * (LoadedCheatTotal - (cheat_num + 1)));
  578.  
  579.     /* knock one off the total */
  580.     LoadedCheatTotal --;
  581. }
  582.  
  583. void subcheat_insert_new (int cheat_num, int subcheat_num)
  584. {
  585.     /* if the index is off the end of the list, fix it */
  586.     if (subcheat_num > CheatTable[cheat_num].num_sub) subcheat_num = CheatTable[cheat_num].num_sub + 1;
  587.  
  588.     /* grow the subcheat table allocation */
  589.     CheatTable[cheat_num].subcheat = realloc (CheatTable[cheat_num].subcheat, sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub + 2));
  590.     if (CheatTable[cheat_num].subcheat == NULL) return;
  591.  
  592.     /* insert space in the middle of the table if needed */
  593.     if ((subcheat_num < CheatTable[cheat_num].num_sub) || (subcheat_num == 0))
  594.         memmove (&CheatTable[cheat_num].subcheat[subcheat_num+1], &CheatTable[cheat_num].subcheat[subcheat_num],
  595.             sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub + 1 - subcheat_num));
  596.  
  597.     /* clear the new entry */
  598.     memset (&CheatTable[cheat_num].subcheat[subcheat_num], 0, sizeof (struct subcheat_struct));
  599.  
  600.     /*add one to the total */
  601.     CheatTable[cheat_num].num_sub ++;
  602. }
  603.  
  604. void subcheat_delete (int cheat_num, int subcheat_num)
  605. {
  606.     if (CheatTable[cheat_num].num_sub < 1) return;
  607.     /* if the index is off the end, make it the last one */
  608.     if (subcheat_num > CheatTable[cheat_num].num_sub) subcheat_num = CheatTable[cheat_num].num_sub;
  609.  
  610.     /* remove the element in the middle if it's not the last */
  611.     if (subcheat_num < CheatTable[cheat_num].num_sub)
  612.         memmove (&CheatTable[cheat_num].subcheat[subcheat_num], &CheatTable[cheat_num].subcheat[subcheat_num+1],
  613.             sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub - subcheat_num));
  614.  
  615.     /* shrink the subcheat table allocation */
  616.     CheatTable[cheat_num].subcheat = realloc (CheatTable[cheat_num].subcheat, sizeof (struct subcheat_struct) * (CheatTable[cheat_num].num_sub));
  617.     if (CheatTable[cheat_num].subcheat == NULL) return;
  618.  
  619.     /* knock one off the total */
  620.     CheatTable[cheat_num].num_sub --;
  621. }
  622.  
  623. /* Function to load the cheats for a game from a single database */
  624. void LoadCheatFile (int merge, char *filename)
  625. {
  626.     void *f = osd_fopen (NULL, filename, OSD_FILETYPE_CHEAT, 0);
  627.     char curline[2048];
  628.     int name_length;
  629.     struct subcheat_struct *subcheat;
  630.     int sub = 0;
  631.  
  632.     if (!merge)
  633.     {
  634.         ActiveCheatTotal = 0;
  635.         LoadedCheatTotal = 0;
  636.     }
  637.  
  638.     if (!f) return;
  639.  
  640.     name_length = strlen (Machine->gamedrv->name);
  641.  
  642.     /* Load the cheats for that game */
  643.     /* Ex.: pacman:0:4E14:06:000:1UP Unlimited lives:Coded on 1 byte */
  644.     while ((osd_fgets (curline, 2048, f) != NULL) && (LoadedCheatTotal < MAX_LOADEDCHEATS))
  645.     {
  646.         char *ptr;
  647.         int temp_cpu;
  648.         offs_t temp_address;
  649.         data_t temp_data;
  650.         INT32 temp_code;
  651.  
  652.  
  653.         /* Take a few easy-out cases to speed things up */
  654.         if (curline[name_length] != ':') continue;
  655.         if (strncmp (curline, Machine->gamedrv->name, name_length) != 0) continue;
  656.         if (curline[0] == ';') continue;
  657.  
  658. #if 0
  659.         if (sologame)
  660.             if ((strstr(str, "2UP") != NULL) || (strstr(str, "PL2") != NULL) ||
  661.                 (strstr(str, "3UP") != NULL) || (strstr(str, "PL3") != NULL) ||
  662.                 (strstr(str, "4UP") != NULL) || (strstr(str, "PL4") != NULL) ||
  663.                 (strstr(str, "2up") != NULL) || (strstr(str, "pl2") != NULL) ||
  664.                 (strstr(str, "3up") != NULL) || (strstr(str, "pl3") != NULL) ||
  665.                 (strstr(str, "4up") != NULL) || (strstr(str, "pl4") != NULL))
  666.           continue;
  667. #endif
  668.  
  669.         /* Extract the fields from the line */
  670.         /* Skip the driver name */
  671.         ptr = strtok(curline, ":");
  672.         if (!ptr) continue;
  673.  
  674.         /* CPU number */
  675.         ptr = strtok(NULL, ":");
  676.         if (!ptr) continue;
  677.         sscanf(ptr,"%d", &temp_cpu);
  678.         /* skip if it's a sound cpu and the audio is off */
  679.         if (CPU_AUDIO_OFF(temp_cpu)) continue;
  680.         /* skip if this is a bogus CPU */
  681.         if (temp_cpu >= cpu_gettotalcpu()) continue;
  682.  
  683.         /* Address */
  684.         ptr = strtok(NULL, ":");
  685.         if (!ptr) continue;
  686.         sscanf(ptr,"%X", &temp_address);
  687.         temp_address &= cpunum_address_mask(temp_cpu);
  688.  
  689.         /* data byte */
  690.         ptr = strtok(NULL, ":");
  691.         if (!ptr) continue;
  692.         sscanf(ptr,"%x", &temp_data);
  693.         temp_data &= 0xff;
  694.  
  695.         /* special code */
  696.         ptr = strtok(NULL, ":");
  697.         if (!ptr) continue;
  698.         sscanf(ptr,"%d", &temp_code);
  699.  
  700.         /* Is this a subcheat? */
  701.         if ((temp_code >= kCheatSpecial_LinkStart) &&
  702.             (temp_code <= kCheatSpecial_LinkEnd))
  703.         {
  704.             sub ++;
  705.  
  706.             /* Adjust the special flag */
  707.             temp_code -= kCheatSpecial_LinkStart;
  708.  
  709.             /* point to the last valid main cheat entry */
  710.             LoadedCheatTotal --;
  711.         }
  712.         else
  713.         {
  714.             /* no, make this the first cheat in the series */
  715.             sub = 0;
  716.         }
  717.  
  718.         /* Allocate (or resize) storage for the subcheat array */
  719.         CheatTable[LoadedCheatTotal].subcheat = realloc (CheatTable[LoadedCheatTotal].subcheat, sizeof (struct subcheat_struct) * (sub + 1));
  720.         if (CheatTable[LoadedCheatTotal].subcheat == NULL) continue;
  721.  
  722.         /* Store the current number of subcheats embodied by this code */
  723.         CheatTable[LoadedCheatTotal].num_sub = sub;
  724.  
  725.         subcheat = &CheatTable[LoadedCheatTotal].subcheat[sub];
  726.  
  727.         /* Reset the cheat */
  728.         subcheat->frames_til_trigger = 0;
  729.         subcheat->frame_count = 0;
  730.         subcheat->backup = 0;
  731.         subcheat->flags = 0;
  732.  
  733.         /* Copy the cheat data */
  734.         subcheat->cpu = temp_cpu;
  735.         subcheat->address = temp_address;
  736.         subcheat->data = temp_data;
  737.         subcheat->code = temp_code;
  738.  
  739.         cheat_set_code (subcheat, temp_code, LoadedCheatTotal);
  740.  
  741.         /* don't bother with the names & comments for subcheats */
  742.         if (sub) goto next;
  743.  
  744.         /* Disable the cheat */
  745.         CheatTable[LoadedCheatTotal].flags &= ~CHEAT_FLAG_ACTIVE;
  746.  
  747.         /* cheat name */
  748.         CheatTable[LoadedCheatTotal].name = NULL;
  749.         ptr = strtok(NULL, ":");
  750.         if (!ptr) continue;
  751.  
  752.         /* Allocate storage and copy the name */
  753.         CheatTable[LoadedCheatTotal].name = malloc (strlen (ptr) + 1);
  754.         strcpy (CheatTable[LoadedCheatTotal].name,ptr);
  755.  
  756.         /* Strip line-ending if needed */
  757.         if (strstr(CheatTable[LoadedCheatTotal].name,"\n") != NULL)
  758.             CheatTable[LoadedCheatTotal].name[strlen(CheatTable[LoadedCheatTotal].name)-1] = 0;
  759.  
  760.         /* read the "comment" field if there */
  761.         ptr = strtok(NULL, ":");
  762.         if (ptr)
  763.         {
  764.             /* Allocate storage and copy the comment */
  765.             CheatTable[LoadedCheatTotal].comment = malloc (strlen (ptr) + 1);
  766.             strcpy(CheatTable[LoadedCheatTotal].comment,ptr);
  767.  
  768.             /* Strip line-ending if needed */
  769.             if (strstr(CheatTable[LoadedCheatTotal].comment,"\n") != NULL)
  770.                 CheatTable[LoadedCheatTotal].comment[strlen(CheatTable[LoadedCheatTotal].comment)-1] = 0;
  771.         }
  772.         else
  773.             CheatTable[LoadedCheatTotal].comment = NULL;
  774.  
  775. next:
  776.         LoadedCheatTotal ++;
  777.     }
  778.  
  779.     osd_fclose (f);
  780. }
  781.  
  782. /* Function who loads the cheats for a game from many databases */
  783. void LoadCheatFiles (void)
  784. {
  785.     char *ptr;
  786.     char str[CHEAT_FILENAME_MAXLEN+1];
  787.     char filename[CHEAT_FILENAME_MAXLEN+1];
  788.  
  789.     int pos1, pos2;
  790.  
  791.     ActiveCheatTotal = 0;
  792.     LoadedCheatTotal = 0;
  793.  
  794.     /* start off with the default cheat file, cheat.dat */
  795.     strcpy (str, cheatfile);
  796.     ptr = strtok (str, ";");
  797.  
  798.     /* append any additional cheat files */
  799.     strcpy (database, ptr);
  800.     strcpy (str, cheatfile);
  801.     str[strlen (str) + 1] = 0;
  802.     pos1 = 0;
  803.     while (str[pos1])
  804.     {
  805.         pos2 = pos1;
  806.         while ((str[pos2]) && (str[pos2] != ';'))
  807.             pos2++;
  808.         if (pos1 != pos2)
  809.         {
  810.             memset (filename, '\0', sizeof(filename));
  811.             strncpy (filename, &str[pos1], (pos2 - pos1));
  812.             LoadCheatFile (1, filename);
  813.             pos1 = pos2 + 1;
  814.         }
  815.     }
  816. }
  817.  
  818. #if 0
  819. void InitMemoryAreas(void)
  820. {
  821.     const struct MemoryWriteAddress *mwa = Machine->drv->cpu[Searchcpu].memory_write;
  822.     char buffer[40];
  823.  
  824.     MemoryAreasSelected = 0;
  825.     MemoryAreasTotal = 0;
  826.  
  827.     while (mwa->start != -1)
  828.     {
  829.         sprintf (buffer, FormatAddr(Searchcpu,0), mwa->start);
  830.         strcpy (MemToScanTable[MemoryAreasTotal].Name, buffer);
  831.         strcat (MemToScanTable[MemoryAreasTotal].Name," -> ");
  832.         sprintf (buffer, FormatAddr(Searchcpu,0), mwa->end);
  833.         strcat (MemToScanTable[MemoryAreasTotal].Name, buffer);
  834.         MemToScanTable[MemoryAreasTotal].handler = mwa->handler;
  835.         MemToScanTable[MemoryAreasTotal].Enabled = 0;
  836.         MemoryAreasTotal++;
  837.         mwa++;
  838.     }
  839. }
  840. #endif
  841.  
  842. /* Init some variables */
  843. void InitCheat(void)
  844. {
  845.     int i;
  846.  
  847.     he_did_cheat = 0;
  848.     CheatEnabled = 1;
  849.  
  850. #if 0
  851.   reset_table (StartRam);
  852.   reset_table (BackupRam);
  853.   reset_table (FlagTable);
  854.  
  855.   reset_table (OldBackupRam);
  856.   reset_table (OldFlagTable);
  857. #endif
  858.  
  859.     /* Reset the watchpoints to their defaults */
  860.     is_watch_active = 0;
  861.     is_watch_visible = 1;
  862.  
  863.     for (i = 0;i < MAX_WATCHES;i ++)
  864.     {
  865.         /* disable this watchpoint */
  866.         watches[i].num_bytes = 0;
  867.  
  868.         watches[i].cpu = 0;
  869.         watches[i].label[0] = 0x00;
  870.         watches[i].label_type = 0;
  871.         watches[i].address = 0;
  872.  
  873.         /* set the screen position */
  874.         watches[i].x = 0;
  875.         watches[i].y = i * Machine->uifontheight;
  876.     }
  877.  
  878.     LoadCheatFiles ();
  879. /*    InitMemoryAreas(); */
  880. }
  881.  
  882. /* copy one cheat structure to another */
  883. void set_cheat(struct cheat_struct *dest, struct cheat_struct *src)
  884. {
  885. // TODO: fix!
  886. #if 0
  887.     /* Changed order to match structure - Added field More */
  888.     struct cheat_struct new_cheat =
  889.     {
  890.         0,                /* cpu */
  891.         0,                /* Address */
  892.         0,                /* Data */
  893.         0,                /* Special */
  894.         0,                /* Count */
  895.         0,                /* Backup */
  896.         0,                /* Minimum */
  897.         0xFF,                /* Maximum */
  898.         "---- New Cheat ----",    /* Name */
  899.         "",                /* More */
  900.         0,                /* active */
  901.     };
  902.  
  903.     if (src == NEW_CHEAT)
  904.     {
  905.         src = &new_cheat;
  906.     }
  907.  
  908.     dest->cpu = src->cpu;
  909.     dest->Address    = src->Address;
  910.     dest->Data        = src->Data;
  911.     dest->Special    = src->Special;
  912.     dest->Count = src->Count;
  913.     dest->Backup    = src->Backup;
  914.     dest->Minimum    = src->Minimum;
  915.     dest->Maximum    = src->Maximum;
  916.     dest->active = src->active;
  917.     strcpy(dest->Name, src->Name);
  918.     strcpy(dest->comment, src->comment);
  919. #endif
  920. }
  921.  
  922. void DeleteLoadedCheatFromTable(int NoCheat)
  923. {
  924.   int i;
  925.   if ((NoCheat > LoadedCheatTotal) || (NoCheat < 0))
  926.     return;
  927.   for (i = NoCheat; i < LoadedCheatTotal-1;i ++)
  928.   {
  929.     set_cheat(&CheatTable[i], &CheatTable[i + 1]);
  930.   }
  931.   LoadedCheatTotal --;
  932. }
  933.  
  934. int EditCheatHeader(void)
  935. {
  936. #if 0
  937.   int i = 0;
  938.   char *paDisplayText[] = {
  939.         "To edit a Cheat name, press",
  940.         "<ENTER> when name is selected.",
  941.         "To edit values or to select a",
  942.         "pre-defined Cheat Name, use :",
  943.         "<+> and Right arrow key: +1",
  944.         "<-> and Left  arrow key: -1",
  945.         "<1> ... <8>: +1 digit",
  946.         "",
  947.         "<F10>: Show Help + other keys",
  948.         0 };
  949.  
  950.   struct DisplayText dt[20];
  951.  
  952.   while (paDisplayText[i])
  953.   {
  954.     if (i)
  955.         dt[i].y = (dt[i - 1].y + FontHeight + 2);
  956.     else
  957.         dt[i].y = FIRSTPOS;
  958.     dt[i].color = UI_COLOR_WHITE;
  959.     dt[i].text = paDisplayText[i];
  960.     dt[i].x = (MachWidth - FontWidth * strlen(dt[i].text)) / 2;
  961.     if(dt[i].x > MachWidth)
  962.         dt[i].x = 0;
  963.     i++;
  964.   }
  965.   dt[i].text = 0; /* terminate array */
  966.   displaytext(dt,0,1);
  967.   return(dt[i-1].y + ( 3 * FontHeight ));
  968. #else
  969.     return 0;
  970. #endif
  971. }
  972.  
  973. void EditCheat(int CheatNo)
  974. {
  975. #if 0
  976.   char *CheatNameList[] = {
  977.     "Infinite Lives PL1",
  978.     "Infinite Lives PL2",
  979.     "Infinite Time",
  980.     "Infinite Time PL1",
  981.     "Infinite Time PL2",
  982.     "Invincibility",
  983.     "Invincibility PL1",
  984.     "Invincibility PL2",
  985.     "Infinite Energy",
  986.     "Infinite Energy PL1",
  987.     "Infinite Energy PL2",
  988.     "Select Next Level",
  989.     "Select Current level",
  990.     "Infinite Ammo",
  991.     "Infinite Ammo PL1",
  992.     "Infinite Ammo PL2",
  993.     "Infinite Bombs",
  994.     "Infinite Bombs PL1",
  995.     "Infinite Bombs PL2",
  996.     "Select Score PL1",
  997.     "Select Score PL2",
  998.     "Drain all Energy Now! PL1",
  999.     "Drain all Energy Now! PL2",
  1000.     "Infinite",
  1001.     "Always have",
  1002.     "Get",
  1003.     "Lose",
  1004.     "[                           ]",
  1005.     "---> <ENTER> To Edit <---",
  1006.     "\0" };
  1007.  
  1008.   int i,s,y,key,done;
  1009.   int total;
  1010.   struct DisplayText dt[20];
  1011.   char str2[6][40];
  1012.   int CurrentName;
  1013.   int EditYPos;
  1014.  
  1015.   char buffer[10];
  1016.  
  1017.   cheat_clearbitmap();
  1018.  
  1019.   y = EditCheatHeader();
  1020.  
  1021.   total = 0;
  1022.  
  1023.   if ((CheatTable[CheatNo].special>= kCheatSpecialUserFirst) && (CheatTable[CheatNo].special<=kCheatSpecialUserLast))
  1024.     CheatTable[CheatNo].data = CheatTable[CheatNo].Maximum;
  1025.  
  1026.   sprintf(str2[0],"Name: %s",CheatTable[CheatNo].Name);
  1027.   if ((FontWidth * (int)strlen(str2[0])) > MachWidth - Machine->uixmin)
  1028.     sprintf(str2[0],"%s",CheatTable[CheatNo].Name);
  1029.   sprintf(str2[1],"CPU:        %01X",CheatTable[CheatNo].cpu);
  1030.  
  1031.   sprintf(str2[2], FormatAddr(CheatTable[CheatNo].cpu,1),
  1032.                 CheatTable[CheatNo].address);
  1033.  
  1034.   sprintf(str2[3],"Value:    %03d  (0x%02X)",CheatTable[CheatNo].data,CheatTable[CheatNo].data);
  1035.   sprintf(str2[4],"Type:     %03d",CheatTable[CheatNo].special);
  1036.  
  1037.   sprintf(str2[5],"comment: %s",CheatTable[CheatNo].comment);
  1038.   if ((FontWidth * (int)strlen(str2[5])) > MachWidth - Machine->uixmin)
  1039.     sprintf(str2[5],"%s",CheatTable[CheatNo].comment);
  1040.  
  1041.   for (i = 0;i < 6;i ++)
  1042.   {
  1043.     dt[total].text = str2[i];
  1044.     dt[total].x = MachWidth / 2;
  1045.     if(MachWidth < 35*FontWidth)
  1046.         dt[total].x = 0;
  1047.     else
  1048.         dt[total].x -= 15*FontWidth;
  1049.     dt[total].y = y;
  1050.     dt[total].color = UI_COLOR_WHITE;
  1051.     total++;
  1052.     y += FontHeight;
  1053.   }
  1054.  
  1055.   dt[total].text = 0; /* terminate array */
  1056.  
  1057.   EditYPos = ( y + ( 4 * FontHeight ) );
  1058.  
  1059.   s = 0;
  1060.   CurrentName = -1;
  1061.  
  1062.   oldkey = 0;
  1063.  
  1064.   done = 0;
  1065.   do
  1066.   {
  1067.  
  1068.     for (i = 0;i < total;i++)
  1069.         dt[i].color = (i == s) ? UI_COLOR_YELLOW : UI_COLOR_WHITE;
  1070.     displaytext(dt,0,1);
  1071.  
  1072.     /* key = keyboard_read_sync(); */
  1073.     key = cheat_readkey();      /* MSH 990217 */
  1074.     switch (key)
  1075.     {
  1076.         case KEYCODE_DOWN:
  1077.         case KEYCODE_2_PAD:
  1078.             if (s < total - 1)
  1079.                 s++;
  1080.             else
  1081.                 s = 0;
  1082.             break;
  1083.  
  1084.         case KEYCODE_UP:
  1085.         case KEYCODE_8_PAD:
  1086.             if (s > 0)
  1087.                 s--;
  1088.             else
  1089.                 s = total - 1;
  1090.             break;
  1091.  
  1092.         case KEYCODE_LEFT:
  1093.         case KEYCODE_4_PAD:
  1094.             switch (s)
  1095.             {
  1096.                 case 0:    /* Name */
  1097.  
  1098.                     if (CurrentName < 0)
  1099.                         CurrentName = 0;
  1100.  
  1101.                     if (CurrentName == 0)                        /* wrap if necessary*/
  1102.                         while (CheatNameList[CurrentName][0])
  1103.                             CurrentName++;
  1104.                     CurrentName--;
  1105.                     strcpy (CheatTable[CheatNo].Name, CheatNameList[CurrentName]);
  1106.                     sprintf (str2[0],"Name: %s", CheatTable[CheatNo].Name);
  1107.                     ClearTextLine(1, dt[0].y);
  1108.                     break;
  1109.                 case 1:    /* cpu */
  1110.                     if (ManyCpus)
  1111.                     {
  1112.                         if (CheatTable[CheatNo].cpu == 0)
  1113.                             CheatTable[CheatNo].cpu = cpu_gettotalcpu() - 1;
  1114.                         else
  1115.                             CheatTable[CheatNo].cpu --;
  1116.                         sprintf (str2[1], "CPU:        %01X", CheatTable[CheatNo].cpu);
  1117.                     }
  1118.                     break;
  1119.                 case 2:    /* Address */
  1120.                     if (CheatTable[CheatNo].address == 0)
  1121.                         CheatTable[CheatNo].address = MAX_ADDRESS(CheatTable[CheatNo].cpu);
  1122.                     else
  1123.                         CheatTable[CheatNo].address --;
  1124.                     sprintf(str2[2], FormatAddr(CheatTable[CheatNo].cpu,1),
  1125.                         CheatTable[CheatNo].address);
  1126.                     break;
  1127.                 case 3:    /* Data */
  1128.                     if (CheatTable[CheatNo].data == 0)
  1129.                         CheatTable[CheatNo].data = 0xFF;
  1130.                     else
  1131.                         CheatTable[CheatNo].data --;
  1132.                     sprintf(str2[3], "Value:    %03d  (0x%02X)", CheatTable[CheatNo].data,
  1133.                         CheatTable[CheatNo].data);
  1134.                     break;
  1135.                 case 4:    /* Special */
  1136.                     if (CheatTable[CheatNo].special <= 0)
  1137.                         CheatTable[CheatNo].special = TOTAL_CHEAT_TYPES + OFFSET_LINK_CHEAT;
  1138.                     else
  1139.                     switch (CheatTable[CheatNo].special)
  1140.                         {
  1141.                             case 20:
  1142.                                 CheatTable[CheatNo].special = 11;
  1143.                                 break;
  1144.                             case 40:
  1145.                                 CheatTable[CheatNo].special = 24;
  1146.                                 break;
  1147.                             case kCheatSpecialUserFirst:
  1148.                                 CheatTable[CheatNo].special = 44;
  1149.                                 break;
  1150.                             case 70:
  1151.                                 CheatTable[CheatNo].special = 65;
  1152.                                 break;
  1153.                             case OFFSET_LINK_CHEAT:
  1154.                                 CheatTable[CheatNo].special = kCheatSpecialUserLast;
  1155.                                 break;
  1156.                             case 20 + OFFSET_LINK_CHEAT:
  1157.                                 CheatTable[CheatNo].special = 11 + OFFSET_LINK_CHEAT;
  1158.                                 break;
  1159.                             case 40 + OFFSET_LINK_CHEAT:
  1160.                                 CheatTable[CheatNo].special = 24 + OFFSET_LINK_CHEAT;
  1161.                                 break;
  1162.                             case kCheatSpecialUserFirst + OFFSET_LINK_CHEAT:
  1163.                                 CheatTable[CheatNo].special = 44 + OFFSET_LINK_CHEAT;
  1164.                                 break;
  1165.                             case 70 + OFFSET_LINK_CHEAT:
  1166.                                 CheatTable[CheatNo].special = 65 + OFFSET_LINK_CHEAT;
  1167.                                 break;
  1168.                             default:
  1169.                                 CheatTable[CheatNo].special --;
  1170.                                 break;
  1171.                         }
  1172.  
  1173.                     sprintf(str2[4],"Type:     %03d",CheatTable[CheatNo].special);
  1174.                     break;
  1175.             }
  1176.             break;
  1177.  
  1178.         case KEYCODE_RIGHT:
  1179.         case KEYCODE_6_PAD:
  1180.             switch (s)
  1181.             {
  1182.                 case 0:    /* Name */
  1183.                     CurrentName ++;
  1184.                     if (CheatNameList[CurrentName][0] == 0)
  1185.                         CurrentName = 0;
  1186.                     strcpy (CheatTable[CheatNo].Name, CheatNameList[CurrentName]);
  1187.                     sprintf (str2[0], "Name: %s", CheatTable[CheatNo].Name);
  1188.                     ClearTextLine(1, dt[0].y);
  1189.                     break;
  1190.                 case 1:    /* cpu */
  1191.                     if (ManyCpus)
  1192.                     {
  1193.                         CheatTable[CheatNo].cpu ++;
  1194.                         if (CheatTable[CheatNo].cpu >= cpu_gettotalcpu())
  1195.                             CheatTable[CheatNo].cpu = 0;
  1196.                         sprintf(str2[1],"CPU:        %01X",CheatTable[CheatNo].cpu);
  1197.                     }
  1198.                     break;
  1199.                 case 2:    /* Address */
  1200.                     CheatTable[CheatNo].address ++;
  1201.                     if (CheatTable[CheatNo].address > MAX_ADDRESS(CheatTable[CheatNo].cpu))
  1202.                         CheatTable[CheatNo].address = 0;
  1203.                     sprintf (str2[2], FormatAddr(CheatTable[CheatNo].cpu,1),
  1204.                         CheatTable[CheatNo].address);
  1205.                     break;
  1206.                 case 3:    /* Data */
  1207.                     if(CheatTable[CheatNo].data == 0xFF)
  1208.                         CheatTable[CheatNo].data = 0;
  1209.                     else
  1210.                         CheatTable[CheatNo].data ++;
  1211.                     sprintf(str2[3],"Value:    %03d  (0x%02X)",CheatTable[CheatNo].data,
  1212.                         CheatTable[CheatNo].data);
  1213.                     break;
  1214.                 case 4:    /* Special */
  1215.                     if (CheatTable[CheatNo].special >= TOTAL_CHEAT_TYPES + OFFSET_LINK_CHEAT)
  1216.                         CheatTable[CheatNo].special = 0;
  1217.                     else
  1218.                     switch (CheatTable[CheatNo].special)
  1219.                         {
  1220.                             case 11:
  1221.                                 CheatTable[CheatNo].special = 20;
  1222.                                 break;
  1223.                             case 24:
  1224.                                 CheatTable[CheatNo].special = 40;
  1225.                                 break;
  1226.                             case 44:
  1227.                                 CheatTable[CheatNo].special = kCheatSpecialUserFirst;
  1228.                                 break;
  1229.                             case 65:
  1230.                                 CheatTable[CheatNo].special = 70;
  1231.                                 break;
  1232.                             case kCheatSpecialUserLast:
  1233.                                 CheatTable[CheatNo].special = OFFSET_LINK_CHEAT;
  1234.                                 break;
  1235.                             case 11 + OFFSET_LINK_CHEAT:
  1236.                                 CheatTable[CheatNo].special = 20 + OFFSET_LINK_CHEAT;
  1237.                                 break;
  1238.                             case 24 + OFFSET_LINK_CHEAT:
  1239.                                 CheatTable[CheatNo].special = 40 + OFFSET_LINK_CHEAT;
  1240.                                 break;
  1241.                             case 44 + OFFSET_LINK_CHEAT:
  1242.                                 CheatTable[CheatNo].special = kCheatSpecialUserFirst + OFFSET_LINK_CHEAT;
  1243.                                 break;
  1244.                             case 65 + OFFSET_LINK_CHEAT:
  1245.                                 CheatTable[CheatNo].special = 70 + OFFSET_LINK_CHEAT;
  1246.                                 break;
  1247.                             default:
  1248.                                 CheatTable[CheatNo].special ++;
  1249.                                 break;
  1250.                         }
  1251.  
  1252.                     sprintf(str2[4],"Type:     %03d",CheatTable[CheatNo].special);
  1253.                     break;
  1254.             }
  1255.             break;
  1256.  
  1257.         case KEYCODE_HOME:
  1258.         case KEYCODE_7_PAD:
  1259.             switch (s)
  1260.             {
  1261.                 case 3: /* Data */
  1262.                     if (CheatTable[CheatNo].data >= 0x80)
  1263.                         CheatTable[CheatNo].data -= 0x80;
  1264.                     sprintf(str2[3], "Value:    %03d  (0x%02X)", CheatTable[CheatNo].data,
  1265.                         CheatTable[CheatNo].data);
  1266.                     break;
  1267.                 case 4: /* Special */
  1268.                     if (CheatTable[CheatNo].special >= OFFSET_LINK_CHEAT)
  1269.                         CheatTable[CheatNo].special -= OFFSET_LINK_CHEAT;
  1270.                     sprintf(str2[4],"Type:     %03d",CheatTable[CheatNo].special);
  1271.                     break;
  1272.             }
  1273.             break;
  1274.  
  1275.         case KEYCODE_END:
  1276.         case KEYCODE_1_PAD:
  1277.             switch (s)
  1278.             {
  1279.                 case 3: /* Data */
  1280.                     if (CheatTable[CheatNo].data < 0x80)
  1281.                         CheatTable[CheatNo].data += 0x80;
  1282.                     sprintf(str2[3], "Value:    %03d  (0x%02X)", CheatTable[CheatNo].data,
  1283.                         CheatTable[CheatNo].data);
  1284.                     break;
  1285.                 case 4: /* Special */
  1286.                     if (CheatTable[CheatNo].special < OFFSET_LINK_CHEAT)
  1287.                         CheatTable[CheatNo].special += OFFSET_LINK_CHEAT;
  1288.                     sprintf(str2[4],"Type:     %03d",CheatTable[CheatNo].special);
  1289.                     break;
  1290.             }
  1291.             break;
  1292.  
  1293.         case KEYCODE_8:
  1294.             if (ADDRESS_BITS(CheatTable[CheatNo].cpu) < 29) break;
  1295.         case KEYCODE_7:
  1296.             if (ADDRESS_BITS(CheatTable[CheatNo].cpu) < 25) break;
  1297.         case KEYCODE_6:
  1298.             if (ADDRESS_BITS(CheatTable[CheatNo].cpu) < 21) break;
  1299.         case KEYCODE_5:
  1300.             if (ADDRESS_BITS(CheatTable[CheatNo].cpu) < 17) break;
  1301.         case KEYCODE_4:
  1302.             if (ADDRESS_BITS(CheatTable[CheatNo].cpu) < 13) break;
  1303.         case KEYCODE_3:
  1304.         case KEYCODE_2:
  1305.         case KEYCODE_1:
  1306.             /* these keys only apply to the address line */
  1307.             if (s == 2)
  1308.             {
  1309.                 int addr = CheatTable[CheatNo].address;    /* copy address*/
  1310.                 int digit = (KEYCODE_8 - key);    /* if key is KEYCODE_8, digit = 0 */
  1311.                 int mask;
  1312.  
  1313.                 /* adjust digit based on cpu address range */
  1314.                 digit -= (8 - (ADDRESS_BITS(CheatTable[CheatNo].cpu)+3) / 4);
  1315.  
  1316.                 mask = 0xF << (digit * 4);    /* if digit is 1, mask = 0xf0 */
  1317.  
  1318.                 do
  1319.                 {
  1320.                 if ((addr & mask) == mask)
  1321.                     /* wrap hex digit around to 0 if necessary */
  1322.                     addr &= ~mask;
  1323.                 else
  1324.                     /* otherwise bump hex digit by 1 */
  1325.                     addr += (0x1 << (digit * 4));
  1326.                 } while (addr > MAX_ADDRESS(CheatTable[CheatNo].cpu));
  1327.  
  1328.                 CheatTable[CheatNo].address = addr;
  1329.                 sprintf(str2[2], FormatAddr(CheatTable[CheatNo].cpu,1),
  1330.                     CheatTable[CheatNo].address);
  1331.             }
  1332.             break;
  1333.  
  1334.         case KEYCODE_F3:
  1335.             while (keyboard_pressed(key)) {}
  1336.           oldkey = 0;
  1337.             switch (s)
  1338.             {
  1339.                 case 2:    /* Address */
  1340.                     for (i = 0; i < total; i++)
  1341.                         dt[i].color = UI_COLOR_WHITE;
  1342.                     displaytext (dt, 0,1);
  1343.                     xprintf (0, 0, EditYPos-2*FontHeight, "Edit Cheat Address:");
  1344.                     sprintf(buffer, FormatAddr(CheatTable[CheatNo].cpu,0),
  1345.                         CheatTable[CheatNo].address);
  1346.                 xedit(0, EditYPos, buffer, strlen(buffer), 1);
  1347.                     sscanf(buffer,"%X", &CheatTable[CheatNo].address);
  1348.                     if (CheatTable[CheatNo].address > MAX_ADDRESS(CheatTable[CheatNo].cpu))
  1349.                         CheatTable[CheatNo].address = MAX_ADDRESS(CheatTable[CheatNo].cpu);
  1350.                     sprintf(str2[2], FormatAddr(CheatTable[CheatNo].cpu,1),
  1351.                         CheatTable[CheatNo].address);
  1352.                     cheat_clearbitmap();
  1353.                     y = EditCheatHeader();
  1354.                   break;
  1355.             }
  1356.             break;
  1357.  
  1358.         case KEYCODE_F10:
  1359.             while (keyboard_pressed(key)) {}
  1360.           oldkey = 0;
  1361.             EditCheatHelp();
  1362.             y = EditCheatHeader();
  1363.             break;
  1364.  
  1365.         case KEYCODE_ENTER:
  1366.         case KEYCODE_ENTER_PAD:
  1367.             while (keyboard_pressed(key)) {}
  1368.           oldkey = 0;
  1369.             switch (s)
  1370.             {
  1371.                 case 0:    /* Name */
  1372.                     for (i = 0; i < total; i++)
  1373.                         dt[i].color = UI_COLOR_WHITE;
  1374.                     displaytext (dt, 0,1);
  1375.                     xprintf (0, 0, EditYPos-2*FontHeight, "Edit Cheat Description:");
  1376.                 xedit(0, EditYPos, CheatTable[CheatNo].Name, CHEAT_NAME_MAXLEN, 0);
  1377.                     sprintf (str2[0], "Name: %s", CheatTable[CheatNo].Name);
  1378.                     if ((FontWidth * (int)strlen(str2[0])) > MachWidth - Machine->uixmin)
  1379.                         sprintf(str2[0],"%s",CheatTable[CheatNo].Name);
  1380.                     cheat_clearbitmap();
  1381.                     y = EditCheatHeader();
  1382.                   break;
  1383.                 case 5:    /* Comment */
  1384.                     for (i = 0; i < total; i++)
  1385.                         dt[i].color = UI_COLOR_WHITE;
  1386.                     displaytext (dt, 0,1);
  1387.                     xprintf (0, 0, EditYPos-2*FontHeight, "Edit Cheat Comment Description:");
  1388.                 xedit(0, EditYPos, CheatTable[CheatNo].comment, CHEAT_NAME_MAXLEN, 0);
  1389.                     sprintf (str2[5], "Comment: %s", CheatTable[CheatNo].comment);
  1390.                     if ((FontWidth * (int)strlen(str2[5])) > MachWidth - Machine->uixmin)
  1391.                         sprintf(str2[5],"%s",CheatTable[CheatNo].comment);
  1392.                     cheat_clearbitmap();
  1393.                     y = EditCheatHeader();
  1394.                   break;
  1395.             }
  1396.             break;
  1397.  
  1398.         case KEYCODE_ESC:
  1399.         case KEYCODE_TAB:
  1400.             while (keyboard_pressed(key)) {}
  1401.             done = 1;
  1402.             break;
  1403.     }
  1404.   } while (done == 0);
  1405.  
  1406.   while (keyboard_pressed(key)) {}
  1407.  
  1408.   if (    (CheatTable[CheatNo].special==62) || (CheatTable[CheatNo].special==65)    ||
  1409.     (CheatTable[CheatNo].special==72) || (CheatTable[CheatNo].special==kCheatSpecialUserLast)    )
  1410.     CheatTable[CheatNo].Minimum = 1;
  1411.   else
  1412.     CheatTable[CheatNo].Minimum = 0;
  1413.   if ((CheatTable[CheatNo].special>= kCheatSpecialUserFirst) && (CheatTable[CheatNo].special<=kCheatSpecialUserLast))
  1414.   {
  1415.     CheatTable[CheatNo].Maximum = CheatTable[CheatNo].data;
  1416.     CheatTable[CheatNo].data = 0;
  1417.   }
  1418.   else
  1419.     CheatTable[CheatNo].Maximum = 0xFF;
  1420.  
  1421.   cheat_clearbitmap();
  1422. #endif
  1423. }
  1424.  
  1425.  
  1426. INT32 EnableDisableCheatMenu (struct osd_bitmap *bitmap, INT32 selected)
  1427. {
  1428.     int sel;
  1429.     static INT8 submenu_choice;
  1430.     const char *menu_item[MAX_LOADEDCHEATS + 2];
  1431.     const char *menu_subitem[MAX_LOADEDCHEATS];
  1432.     char buf[MAX_LOADEDCHEATS][80];
  1433.     char buf2[MAX_LOADEDCHEATS][10];
  1434.     static int tag[MAX_LOADEDCHEATS];
  1435.     int i, total = 0;
  1436.  
  1437.  
  1438.     sel = selected - 1;
  1439.  
  1440.     /* If a submenu has been selected, go there */
  1441.     if (submenu_choice)
  1442.     {
  1443.         submenu_choice = CommentMenu (bitmap, submenu_choice, tag[sel]);
  1444.         if (submenu_choice == -1)
  1445.         {
  1446.             submenu_choice = 0;
  1447.             sel = -2;
  1448.         }
  1449.  
  1450.         return sel + 1;
  1451.     }
  1452.  
  1453.     /* No submenu active, do the watchpoint menu */
  1454.     for (i = 0; i < LoadedCheatTotal; i ++)
  1455.     {
  1456.         int string_num;
  1457.  
  1458.         if (CheatTable[i].comment && (CheatTable[i].comment[0] != 0x00))
  1459.         {
  1460.             sprintf (buf[total], "%s (%s...)", CheatTable[i].name, ui_getstring (UI_moreinfo));
  1461.         }
  1462.         else
  1463.             sprintf (buf[total], "%s", CheatTable[i].name);
  1464.  
  1465.         tag[total] = i;
  1466.         menu_item[total] = buf[total];
  1467.  
  1468.         /* add submenu options for all cheats that are not comments */
  1469.         if ((CheatTable[i].flags & CHEAT_FLAG_COMMENT) == 0)
  1470.         {
  1471.             if (CheatTable[i].flags & CHEAT_FLAG_ACTIVE)
  1472.                 string_num = UI_on;
  1473.             else
  1474.                 string_num = UI_off;
  1475.             sprintf (buf2[total], "%s", ui_getstring (string_num));
  1476.             menu_subitem[total] = buf2[total];
  1477.         }
  1478.         else
  1479.             menu_subitem[total] = NULL;
  1480.         total ++;
  1481.     }
  1482.  
  1483.     menu_item[total] = ui_getstring (UI_returntoprior);
  1484.     menu_subitem[total++] = NULL;
  1485.     menu_item[total] = 0;    /* terminate array */
  1486.  
  1487.     ui_displaymenu(bitmap,menu_item,menu_subitem,0,sel,0);
  1488.  
  1489.     if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
  1490.         sel = (sel + 1) % total;
  1491.  
  1492.     if (input_ui_pressed_repeat(IPT_UI_UP,8))
  1493.         sel = (sel + total - 1) % total;
  1494.  
  1495.     if ((input_ui_pressed_repeat(IPT_UI_LEFT,8)) || (input_ui_pressed_repeat(IPT_UI_RIGHT,8)))
  1496.     {
  1497.         if ((CheatTable[tag[sel]].flags & CHEAT_FLAG_COMMENT) == 0)
  1498.         {
  1499.             int active = CheatTable[tag[sel]].flags & CHEAT_FLAG_ACTIVE;
  1500.  
  1501.             active ^= 0x01;
  1502.  
  1503.             cheat_set_status (tag[sel], active);
  1504.             CheatEnabled = 1;
  1505.         }
  1506.     }
  1507.  
  1508.  
  1509.     if (input_ui_pressed(IPT_UI_SELECT))
  1510.     {
  1511.         if (sel == (total - 1))
  1512.         {
  1513.             /* return to prior menu */
  1514.             submenu_choice = 0;
  1515.             sel = -1;
  1516.         }
  1517.         else
  1518.         {
  1519.             if (CheatTable[tag[sel]].comment && (CheatTable[tag[sel]].comment[0] != 0x00))
  1520.             {
  1521.                 submenu_choice = 1;
  1522.                 /* tell updatescreen() to clean after us */
  1523.                 need_to_clear_bitmap = 1;
  1524.             }
  1525.         }
  1526.     }
  1527.  
  1528.     /* Cancel pops us up a menu level */
  1529.     if (input_ui_pressed(IPT_UI_CANCEL))
  1530.         sel = -1;
  1531.  
  1532.     /* The UI key takes us all the way back out */
  1533.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  1534.         sel = -2;
  1535.  
  1536.     if (sel == -1 || sel == -2)
  1537.     {
  1538.         /* tell updatescreen() to clean after us */
  1539.         need_to_clear_bitmap = 1;
  1540.     }
  1541.  
  1542.     return sel + 1;
  1543. }
  1544.  
  1545. static INT32 CommentMenu (struct osd_bitmap *bitmap, INT32 selected, int cheat_index)
  1546. {
  1547.     char buf[2048];
  1548.     char buf2[256];
  1549.     int sel;
  1550.  
  1551.  
  1552.     sel = selected - 1;
  1553.  
  1554.     buf[0] = 0;
  1555.  
  1556.     if (CheatTable[cheat_index].comment[0] == 0x00)
  1557.     {
  1558.         sel = -1;
  1559.         buf[0] = 0;
  1560.     }
  1561.     else
  1562.     {
  1563.         sprintf (buf2, "\t%s\n\t%s\n\n", ui_getstring (UI_moreinfoheader), CheatTable[cheat_index].name);
  1564.         strcpy (buf, buf2);
  1565.         strcat (buf, CheatTable[cheat_index].comment);
  1566.     }
  1567.  
  1568.     /* menu system, use the normal menu keys */
  1569.     strcat(buf,"\n\n\t");
  1570.     strcat(buf,ui_getstring (UI_lefthilight));
  1571.     strcat(buf," ");
  1572.     strcat(buf,ui_getstring (UI_returntoprior));
  1573.     strcat(buf," ");
  1574.     strcat(buf,ui_getstring (UI_righthilight));
  1575.  
  1576.     ui_displaymessagewindow(bitmap, buf);
  1577.  
  1578.     if (input_ui_pressed(IPT_UI_SELECT))
  1579.         sel = -1;
  1580.  
  1581.     if (input_ui_pressed(IPT_UI_CANCEL))
  1582.         sel = -1;
  1583.  
  1584.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  1585.         sel = -2;
  1586.  
  1587.     if (sel == -1 || sel == -2)
  1588.     {
  1589.         /* tell updatescreen() to clean after us */
  1590.         need_to_clear_bitmap = 1;
  1591.     }
  1592.  
  1593.     return sel + 1;
  1594. }
  1595.  
  1596. INT32 AddEditCheatMenu (struct osd_bitmap *bitmap, INT32 selected)
  1597. {
  1598.     int sel;
  1599.     static INT8 submenu_choice;
  1600.     const char *menu_item[MAX_LOADEDCHEATS + 4];
  1601. //    char buf[MAX_LOADEDCHEATS][80];
  1602. //    char buf2[MAX_LOADEDCHEATS][10];
  1603.     int tag[MAX_LOADEDCHEATS];
  1604.     int i, total = 0;
  1605.  
  1606.  
  1607.     sel = selected - 1;
  1608.  
  1609.     /* Set up the "tag" table so we know which cheats belong in the menu */
  1610.     for (i = 0; i < LoadedCheatTotal; i ++)
  1611.     {
  1612.         /* add menu listings for all cheats that are not comments */
  1613.         if ((CheatTable[i].flags & CHEAT_FLAG_COMMENT) == 0)
  1614.         {
  1615.             tag[total] = i;
  1616.             menu_item[total++] = CheatTable[i].name;
  1617.         }
  1618.     }
  1619.  
  1620.     /* If a submenu has been selected, go there */
  1621.     if (submenu_choice)
  1622.     {
  1623.         submenu_choice = EditCheatMenu (bitmap, submenu_choice, tag[sel]);
  1624.         if (submenu_choice == -1)
  1625.         {
  1626.             submenu_choice = 0;
  1627.             sel = -2;
  1628.         }
  1629.  
  1630.         return sel + 1;
  1631.     }
  1632.  
  1633.     /* No submenu active, do the watchpoint menu */
  1634.     menu_item[total++] = ui_getstring (UI_returntoprior);
  1635.     menu_item[total] = NULL; /* TODO: add help string */
  1636.     menu_item[total+1] = 0;    /* terminate array */
  1637.  
  1638.     ui_displaymenu(bitmap,menu_item,0,0,sel,0);
  1639.  
  1640.     if (code_pressed_memory_repeat (KEYCODE_INSERT, 8))
  1641.     {
  1642.         /* add a new cheat at the current position (or the end) */
  1643.         if (sel < total - 1)
  1644.             cheat_insert_new (tag[sel]);
  1645.         else
  1646.             cheat_insert_new (LoadedCheatTotal);
  1647.     }
  1648.  
  1649.     if (code_pressed_memory_repeat (KEYCODE_DEL, 8))
  1650.     {
  1651.         if (LoadedCheatTotal)
  1652.         {
  1653.             /* delete the selected cheat (or the last one) */
  1654.             if (sel < total - 1)
  1655.                 cheat_delete (tag[sel]);
  1656.             else
  1657.             {
  1658.                 cheat_delete (LoadedCheatTotal - 1);
  1659.                 sel = total - 2;
  1660.             }
  1661.         }
  1662.     }
  1663.  
  1664.     if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
  1665.         sel = (sel + 1) % total;
  1666.  
  1667.     if (input_ui_pressed_repeat(IPT_UI_UP,8))
  1668.         sel = (sel + total - 1) % total;
  1669.  
  1670.     if (input_ui_pressed(IPT_UI_SELECT))
  1671.     {
  1672.         if (sel == (total - 1))
  1673.         {
  1674.             /* return to prior menu */
  1675.             submenu_choice = 0;
  1676.             sel = -1;
  1677.         }
  1678.         else
  1679.         {
  1680.             submenu_choice = 1;
  1681.             /* tell updatescreen() to clean after us */
  1682.             need_to_clear_bitmap = 1;
  1683.         }
  1684.     }
  1685.  
  1686.     /* Cancel pops us up a menu level */
  1687.     if (input_ui_pressed(IPT_UI_CANCEL))
  1688.         sel = -1;
  1689.  
  1690.     /* The UI key takes us all the way back out */
  1691.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  1692.         sel = -2;
  1693.  
  1694.     if (sel == -1 || sel == -2)
  1695.     {
  1696.         /* tell updatescreen() to clean after us */
  1697.         need_to_clear_bitmap = 1;
  1698.     }
  1699.  
  1700.     return sel + 1;
  1701. }
  1702.  
  1703. static INT32 EditCheatMenu (struct osd_bitmap *bitmap, INT32 selected, UINT8 cheat_num)
  1704. {
  1705.     int sel;
  1706.     int total, total2;
  1707.     struct subcheat_struct *subcheat;
  1708.     static INT8 submenu_choice;
  1709.     static UINT8 textedit_active;
  1710.     const char *menu_item[40];
  1711.     const char *menu_subitem[40];
  1712.     char setting[40][30];
  1713.     char flag[40];
  1714.     int arrowize;
  1715.     int subcheat_num;
  1716.     int i;
  1717.  
  1718.  
  1719.     sel = selected - 1;
  1720.  
  1721.     total = 0;
  1722.     /* No submenu active, display the main cheat menu */
  1723.     menu_item[total++] = ui_getstring (UI_cheatname);
  1724.     menu_item[total++] = ui_getstring (UI_cheatdescription);
  1725.     for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
  1726.     {
  1727.         menu_item[total++] = ui_getstring (UI_cpu);
  1728.         menu_item[total++] = ui_getstring (UI_address);
  1729.         menu_item[total++] = ui_getstring (UI_value);
  1730.         menu_item[total++] = ui_getstring (UI_code);
  1731.     }
  1732.     menu_item[total++] = ui_getstring (UI_returntoprior);
  1733.     menu_item[total] = 0;
  1734.  
  1735.     arrowize = 0;
  1736.  
  1737.     /* set up the submenu selections */
  1738.     total2 = 0;
  1739.     for (i = 0; i < 40; i ++)
  1740.         flag[i] = 0;
  1741.  
  1742.     /* if we're editing the label, make it inverse */
  1743.     if (textedit_active)
  1744.         flag[sel] = 1;
  1745.  
  1746.     /* name */
  1747.     if (CheatTable[cheat_num].name != 0x00)
  1748.         sprintf (setting[total2], "%s", CheatTable[cheat_num].name);
  1749.     else
  1750.         strcpy (setting[total2], ui_getstring (UI_none));
  1751.     menu_subitem[total2] = setting[total2]; total2++;
  1752.  
  1753.     /* comment */
  1754.     if (CheatTable[cheat_num].comment && CheatTable[cheat_num].comment != 0x00)
  1755.         sprintf (setting[total2], "%s...", ui_getstring (UI_moreinfo));
  1756.     else
  1757.         strcpy (setting[total2], ui_getstring (UI_none));
  1758.     menu_subitem[total2] = setting[total2]; total2++;
  1759.  
  1760.     /* Subcheats */
  1761.     for (i = 0; i <= CheatTable[cheat_num].num_sub; i ++)
  1762.     {
  1763.         subcheat = &CheatTable[cheat_num].subcheat[i];
  1764.  
  1765.         /* cpu number */
  1766.         sprintf (setting[total2], "%d", subcheat->cpu);
  1767.         menu_subitem[total2] = setting[total2]; total2++;
  1768.  
  1769.         /* address */
  1770.         if (cpunum_address_bits(subcheat->cpu) <= 16)
  1771.         {
  1772.             sprintf (setting[total2], "%04X", subcheat->address);
  1773.         }
  1774.         else
  1775.         {
  1776.             sprintf (setting[total2], "%08X", subcheat->address);
  1777.         }
  1778.         menu_subitem[total2] = setting[total2]; total2++;
  1779.  
  1780.         /* value */
  1781.         sprintf (setting[total2], "%d", subcheat->data);
  1782.         menu_subitem[total2] = setting[total2]; total2++;
  1783.  
  1784.         /* code */
  1785.         sprintf (setting[total2], "%d", subcheat->code);
  1786.         menu_subitem[total2] = setting[total2]; total2++;
  1787.  
  1788.         menu_subitem[total2] = NULL;
  1789.     }
  1790.  
  1791.     ui_displaymenu(bitmap,menu_item,menu_subitem,flag,sel,arrowize);
  1792.  
  1793.     if (code_pressed_memory_repeat (KEYCODE_INSERT, 8))
  1794.     {
  1795.         if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub + 1) * 4) + 1))
  1796.         {
  1797.             subcheat_num = (sel - 2) % 4;
  1798.         }
  1799.         else
  1800.         {
  1801.             subcheat_num = CheatTable[cheat_num].num_sub + 1;
  1802.         }
  1803.  
  1804.         /* add a new subcheat at the current position (or the end) */
  1805.         subcheat_insert_new (cheat_num, subcheat_num);
  1806.     }
  1807.  
  1808.     if (code_pressed_memory_repeat (KEYCODE_DEL, 8))
  1809.     {
  1810.         if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub + 1) * 4) + 1))
  1811.         {
  1812.             subcheat_num = (sel - 2) % 4;
  1813.         }
  1814.         else
  1815.         {
  1816.             subcheat_num = CheatTable[cheat_num].num_sub;
  1817.         }
  1818.  
  1819.         if (CheatTable[cheat_num].num_sub != 0)
  1820.             subcheat_delete (cheat_num, subcheat_num);
  1821.     }
  1822.  
  1823.     if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
  1824.     {
  1825.         textedit_active = 0;
  1826.         sel = (sel + 1) % total;
  1827.     }
  1828.  
  1829.     if (input_ui_pressed_repeat(IPT_UI_UP,8))
  1830.     {
  1831.         textedit_active = 0;
  1832.         sel = (sel + total - 1) % total;
  1833.     }
  1834.  
  1835.     if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
  1836.     {
  1837.         if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub + 1) * 4) + 1))
  1838.         {
  1839.             int newsel;
  1840.  
  1841.             subcheat = &CheatTable[cheat_num].subcheat[(sel - 2) / 4];
  1842.             newsel = (sel - 2) % 4;
  1843.  
  1844.             switch (newsel)
  1845.             {
  1846.                 case 0: /* CPU */
  1847.                     subcheat->cpu --;
  1848.                     /* skip audio CPUs when the sound is off */
  1849.                     if (CPU_AUDIO_OFF(subcheat->cpu))
  1850.                         subcheat->cpu --;
  1851.                     if (subcheat->cpu < 0)
  1852.                         subcheat->cpu = cpu_gettotalcpu() - 1;
  1853.                     subcheat->address &= cpunum_address_mask(subcheat->cpu);
  1854.                     break;
  1855.                 case 1: /* address */
  1856.                     textedit_active = 0;
  1857.                     subcheat->address --;
  1858.                     subcheat->address &= cpunum_address_mask(subcheat->cpu);
  1859.                     break;
  1860.                 case 2: /* value */
  1861.                     textedit_active = 0;
  1862.                     subcheat->data --;
  1863.                     subcheat->data &= 0xff;
  1864.                     break;
  1865.                 case 3: /* code */
  1866.                     textedit_active = 0;
  1867.                     subcheat->code --;
  1868.                     break;
  1869.             }
  1870.         }
  1871.     }
  1872.  
  1873.     if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
  1874.     {
  1875.         if ((sel >= 2) && (sel <= ((CheatTable[cheat_num].num_sub+1) * 4) + 1))
  1876.         {
  1877.             int newsel;
  1878.  
  1879.             subcheat = &CheatTable[cheat_num].subcheat[(sel - 2) / 4];
  1880.             newsel = (sel - 2) % 4;
  1881.  
  1882.             switch (newsel)
  1883.             {
  1884.                 case 0: /* CPU */
  1885.                     subcheat->cpu ++;
  1886.                     /* skip audio CPUs when the sound is off */
  1887.                     if (CPU_AUDIO_OFF(subcheat->cpu))
  1888.                         subcheat->cpu ++;
  1889.                     if (subcheat->cpu >= cpu_gettotalcpu())
  1890.                         subcheat->cpu = 0;
  1891.                     subcheat->address &= cpunum_address_mask(subcheat->cpu);
  1892.                     break;
  1893.                 case 1: /* address */
  1894.                     textedit_active = 0;
  1895.                     subcheat->address ++;
  1896.                     subcheat->address &= cpunum_address_mask(subcheat->cpu);
  1897.                     break;
  1898.                 case 2: /* value */
  1899.                     textedit_active = 0;
  1900.                     subcheat->data ++;
  1901.                     subcheat->data &= 0xff;
  1902.                     break;
  1903.                 case 3: /* code */
  1904.                     textedit_active = 0;
  1905.                     subcheat->code ++;
  1906.                     break;
  1907.             }
  1908.         }
  1909.     }
  1910.  
  1911.     if (input_ui_pressed(IPT_UI_SELECT))
  1912.     {
  1913.         if (sel == ((CheatTable[cheat_num].num_sub+1) * 4) + 2)
  1914.         {
  1915.             /* return to main menu */
  1916.             submenu_choice = 0;
  1917.             sel = -1;
  1918.         }
  1919.         else if (/*(sel == 4) ||*/ (sel == 0))
  1920.         {
  1921.             /* wait for key up */
  1922.             while (input_ui_pressed(IPT_UI_SELECT)) {};
  1923.  
  1924.             /* flush the text buffer */
  1925.             osd_readkey_unicode (1);
  1926.             textedit_active ^= 1;
  1927.         }
  1928.         else
  1929.         {
  1930.             submenu_choice = 1;
  1931.             /* tell updatescreen() to clean after us */
  1932.             need_to_clear_bitmap = 1;
  1933.         }
  1934.     }
  1935.  
  1936.     /* Cancel pops us up a menu level */
  1937.     if (input_ui_pressed(IPT_UI_CANCEL))
  1938.         sel = -1;
  1939.  
  1940.     /* The UI key takes us all the way back out */
  1941.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  1942.         sel = -2;
  1943.  
  1944.     if (sel == -1 || sel == -2)
  1945.     {
  1946.         textedit_active = 0;
  1947.         /* flush the text buffer */
  1948.         osd_readkey_unicode (1);
  1949.         /* tell updatescreen() to clean after us */
  1950.         need_to_clear_bitmap = 1;
  1951.     }
  1952.  
  1953.     /* After we've weeded out any control characters, look for text */
  1954.     if (textedit_active)
  1955.     {
  1956.         int code;
  1957.  
  1958. #if 0
  1959.         /* is this the address field? */
  1960.         if (sel == 1)
  1961.         {
  1962.             INT8 hex_val;
  1963.  
  1964.             /* see if a hex digit was typed */
  1965.             hex_val = code_read_hex_async();
  1966.             if (hex_val != -1)
  1967.             {
  1968.                 /* shift over one digit, add in the new value and clip */
  1969.                 subcheat->address <<= 4;
  1970.                 subcheat->address |= hex_val;
  1971.                 subcheat->address &= cpunum_address_mask(subcheat->cpu);
  1972.             }
  1973.         }
  1974.         else
  1975. #endif
  1976.         if (CheatTable[cheat_num].name)
  1977.         {
  1978.             int length = strlen(CheatTable[cheat_num].name);
  1979.  
  1980.             code = osd_readkey_unicode(0) & 0xff; /* no 16-bit support */
  1981.  
  1982.             if (code)
  1983.             {
  1984.                 if (code == 0x08) /* backspace */
  1985.                 {
  1986.                     /* clear the buffer */
  1987.                     CheatTable[cheat_num].name[0] = 0x00;
  1988.                 }
  1989.                 else
  1990.                 {
  1991.                     /* append the character */
  1992.                     CheatTable[cheat_num].name = realloc (CheatTable[cheat_num].name, length + 2);
  1993.                     if (CheatTable[cheat_num].name != NULL)
  1994.                     {
  1995.                         CheatTable[cheat_num].name[length] = code;
  1996.                         CheatTable[cheat_num].name[length+1] = 0x00;
  1997.                     }
  1998.                 }
  1999.             }
  2000.         }
  2001.     }
  2002.  
  2003.     return sel + 1;
  2004. }
  2005.  
  2006.  
  2007. #ifdef macintosh
  2008. #pragma mark -
  2009. #endif
  2010.  
  2011. INT32 StartSearch (INT32 selected)
  2012. {
  2013.     return -1;
  2014. }
  2015.  
  2016. INT32 ContinueSearch (INT32 selected, int ViewLast)
  2017. {
  2018.     return -1;
  2019. }
  2020.  
  2021. INT32 RestoreSearch (INT32 selected)
  2022. {
  2023.     return -1;
  2024. }
  2025.  
  2026. #ifdef macintosh
  2027. #pragma mark -
  2028. #endif
  2029.  
  2030. int FindFreeWatch (void)
  2031. {
  2032.     int i;
  2033.     for (i = 0; i < MAX_WATCHES; i ++)
  2034.     {
  2035.         if (watches[i].num_bytes == 0)
  2036.             return i;
  2037.     }
  2038.  
  2039.     /* indicate no free watch found */
  2040.     return -1;
  2041. }
  2042.  
  2043. void DisplayWatches (struct osd_bitmap *bitmap)
  2044. {
  2045.     int i;
  2046.     char buf[256];
  2047.  
  2048.     if ((!is_watch_active) || (!is_watch_visible)) return;
  2049.  
  2050.     for (i = 0; i < MAX_WATCHES; i++)
  2051.     {
  2052.         /* Is this watchpoint active? */
  2053.         if (watches[i].num_bytes != 0)
  2054.         {
  2055.             char buf2[80];
  2056.  
  2057.             /* Display the first byte */
  2058.             sprintf (buf, "%02x", computer_readmem_byte (watches[i].cpu, watches[i].address));
  2059.  
  2060.             /* If this is for more than one byte, display the rest */
  2061.             if (watches[i].num_bytes > 1)
  2062.             {
  2063.                 int j;
  2064.  
  2065.                 for (j = 1; j < watches[i].num_bytes; j ++)
  2066.                 {
  2067.                     sprintf (buf2, " %02x", computer_readmem_byte (watches[i].cpu, watches[i].address + j));
  2068.                     strcat (buf, buf2);
  2069.                 }
  2070.             }
  2071.  
  2072.             /* Handle any labels */
  2073.             switch (watches[i].label_type)
  2074.             {
  2075.                 case 0:
  2076.                 default:
  2077.                     break;
  2078.                 case 1:
  2079.                     if (cpunum_address_bits(watches[i].cpu) <= 16)
  2080.                     {
  2081.                         sprintf (buf2, " (%04x)", watches[i].address);
  2082.                         strcat (buf, buf2);
  2083.                     }
  2084.                     else
  2085.                     {
  2086.                         sprintf (buf2, " (%08x)", watches[i].address);
  2087.                         strcat (buf, buf2);
  2088.                     }
  2089.                     break;
  2090.                 case 2:
  2091.                     {
  2092.                         sprintf (buf2, " (%s)", watches[i].label);
  2093.                         strcat (buf, buf2);
  2094.                     }
  2095.                     break;
  2096.             }
  2097.  
  2098.             ui_text (bitmap, buf, watches[i].x, watches[i].y);
  2099.         }
  2100.     }
  2101. }
  2102.  
  2103. INT32 ConfigureWatch (struct osd_bitmap *bitmap, INT32 selected, UINT8 watchnum)
  2104. {
  2105. #ifdef NUM_ENTRIES
  2106. #undef NUM_ENTRIES
  2107. #endif
  2108. #define NUM_ENTRIES 9
  2109.  
  2110.     int sel;
  2111.     int total, total2;
  2112.     static INT8 submenu_choice;
  2113.     static UINT8 textedit_active;
  2114.     const char *menu_item[NUM_ENTRIES];
  2115.     const char *menu_subitem[NUM_ENTRIES];
  2116.     char setting[NUM_ENTRIES][30];
  2117.     char flag[NUM_ENTRIES];
  2118.     int arrowize;
  2119.     int i;
  2120.  
  2121.  
  2122.     sel = selected - 1;
  2123.  
  2124.     total = 0;
  2125.     /* No submenu active, display the main cheat menu */
  2126.     menu_item[total++] = ui_getstring (UI_cpu);
  2127.     menu_item[total++] = ui_getstring (UI_address);
  2128.     menu_item[total++] = ui_getstring (UI_watchlength);
  2129.     menu_item[total++] = ui_getstring (UI_watchlabeltype);
  2130.     menu_item[total++] = ui_getstring (UI_watchlabel);
  2131.     menu_item[total++] = ui_getstring (UI_watchx);
  2132.     menu_item[total++] = ui_getstring (UI_watchy);
  2133.     menu_item[total++] = ui_getstring (UI_returntoprior);
  2134.     menu_item[total] = 0;
  2135.  
  2136.     arrowize = 0;
  2137.  
  2138.     /* set up the submenu selections */
  2139.     total2 = 0;
  2140.     for (i = 0; i < NUM_ENTRIES; i ++)
  2141.         flag[i] = 0;
  2142.  
  2143.     /* if we're editing the label, make it inverse */
  2144.     if (textedit_active)
  2145.         flag[sel] = 1;
  2146.  
  2147.     /* cpu number */
  2148.     sprintf (setting[total2], "%d", watches[watchnum].cpu);
  2149.     menu_subitem[total2] = setting[total2]; total2++;
  2150.  
  2151.     /* address */
  2152.     if (cpunum_address_bits(watches[watchnum].cpu) <= 16)
  2153.     {
  2154.         sprintf (setting[total2], "%04x", watches[watchnum].address);
  2155.     }
  2156.     else
  2157.     {
  2158.         sprintf (setting[total2], "%08x", watches[watchnum].address);
  2159.     }
  2160.     menu_subitem[total2] = setting[total2]; total2++;
  2161.  
  2162.     /* length */
  2163.     sprintf (setting[total2], "%d", watches[watchnum].num_bytes);
  2164.     menu_subitem[total2] = setting[total2]; total2++;
  2165.  
  2166.     /* label type */
  2167.     switch (watches[watchnum].label_type)
  2168.     {
  2169.         case 0:
  2170.             strcpy (setting[total2], ui_getstring (UI_none));
  2171.             break;
  2172.         case 1:
  2173.             strcpy (setting[total2], ui_getstring (UI_address));
  2174.             break;
  2175.         case 2:
  2176.             strcpy (setting[total2], ui_getstring (UI_text));
  2177.             break;
  2178.     }
  2179.     menu_subitem[total2] = setting[total2]; total2++;
  2180.  
  2181.     /* label */
  2182.     if (watches[watchnum].label[0] != 0x00)
  2183.         sprintf (setting[total2], "%s", watches[watchnum].label);
  2184.     else
  2185.         strcpy (setting[total2], ui_getstring (UI_none));
  2186.     menu_subitem[total2] = setting[total2]; total2++;
  2187.  
  2188.     /* x */
  2189.     sprintf (setting[total2], "%d", watches[watchnum].x);
  2190.     menu_subitem[total2] = setting[total2]; total2++;
  2191.  
  2192.     /* y */
  2193.     sprintf (setting[total2], "%d", watches[watchnum].y);
  2194.     menu_subitem[total2] = setting[total2]; total2++;
  2195.  
  2196.     menu_subitem[total2] = NULL;
  2197.  
  2198.     ui_displaymenu(bitmap,menu_item,menu_subitem,flag,sel,arrowize);
  2199.  
  2200.     if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
  2201.     {
  2202.         textedit_active = 0;
  2203.         sel = (sel + 1) % total;
  2204.     }
  2205.  
  2206.     if (input_ui_pressed_repeat(IPT_UI_UP,8))
  2207.     {
  2208.         textedit_active = 0;
  2209.         sel = (sel + total - 1) % total;
  2210.     }
  2211.  
  2212.     if (input_ui_pressed_repeat(IPT_UI_LEFT,8))
  2213.     {
  2214.         switch (sel)
  2215.         {
  2216.             case 0: /* CPU */
  2217.                 watches[watchnum].cpu --;
  2218.                 /* skip audio CPUs when the sound is off */
  2219.                 if (CPU_AUDIO_OFF(watches[watchnum].cpu))
  2220.                     watches[watchnum].cpu --;
  2221.                 if (watches[watchnum].cpu < 0)
  2222.                     watches[watchnum].cpu = cpu_gettotalcpu() - 1;
  2223.                 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
  2224.                 break;
  2225.             case 1: /* address */
  2226.                 textedit_active = 0;
  2227.                 watches[watchnum].address --;
  2228.                 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
  2229.                 break;
  2230.             case 2: /* number of bytes */
  2231.                 watches[watchnum].num_bytes --;
  2232.                 if (watches[watchnum].num_bytes == (UINT8) -1)
  2233.                     watches[watchnum].num_bytes = 16;
  2234.                 break;
  2235.             case 3: /* label type */
  2236.                 watches[watchnum].label_type --;
  2237.                 if (watches[watchnum].label_type == (UINT8) -1)
  2238.                     watches[watchnum].label_type = 2;
  2239.                 break;
  2240.             case 4: /* label string */
  2241.                 textedit_active = 0;
  2242.                 break;
  2243.             case 5: /* x */
  2244.                 watches[watchnum].x --;
  2245.                 if (watches[watchnum].x == (UINT16) -1)
  2246.                     watches[watchnum].x = Machine->uiwidth - 1;
  2247.                 break;
  2248.             case 6: /* y */
  2249.                 watches[watchnum].y --;
  2250.                 if (watches[watchnum].y == (UINT16) -1)
  2251.                     watches[watchnum].y = Machine->uiheight - 1;
  2252.                 break;
  2253.         }
  2254.     }
  2255.  
  2256.     if (input_ui_pressed_repeat(IPT_UI_RIGHT,8))
  2257.     {
  2258.         switch (sel)
  2259.         {
  2260.             case 0:
  2261.                 watches[watchnum].cpu ++;
  2262.                 /* skip audio CPUs when the sound is off */
  2263.                 if (CPU_AUDIO_OFF(watches[watchnum].cpu))
  2264.                     watches[watchnum].cpu ++;
  2265.                 if (watches[watchnum].cpu >= cpu_gettotalcpu())
  2266.                     watches[watchnum].cpu = 0;
  2267.                 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
  2268.                 break;
  2269.             case 1:
  2270.                 textedit_active = 0;
  2271.                 watches[watchnum].address ++;
  2272.                 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
  2273.                 break;
  2274.             case 2:
  2275.                 watches[watchnum].num_bytes ++;
  2276.                 if (watches[watchnum].num_bytes > 16)
  2277.                     watches[watchnum].num_bytes = 0;
  2278.                 break;
  2279.             case 3:
  2280.                 watches[watchnum].label_type ++;
  2281.                 if (watches[watchnum].label_type > 2)
  2282.                     watches[watchnum].label_type = 0;
  2283.                 break;
  2284.             case 4:
  2285.                 textedit_active = 0;
  2286.                 break;
  2287.             case 5:
  2288.                 watches[watchnum].x ++;
  2289.                 if (watches[watchnum].x >= Machine->uiwidth)
  2290.                     watches[watchnum].x = 0;
  2291.                 break;
  2292.             case 6:
  2293.                 watches[watchnum].y ++;
  2294.                 if (watches[watchnum].y >= Machine->uiheight)
  2295.                     watches[watchnum].y = 0;
  2296.                 break;
  2297.         }
  2298.     }
  2299.  
  2300.     /* see if any watchpoints are active and set the flag if so */
  2301.     is_watch_active = 0;
  2302.     for (i = 0; i < MAX_WATCHES; i ++)
  2303.     {
  2304.         if (watches[i].num_bytes != 0)
  2305.         {
  2306.             is_watch_active = 1;
  2307.             break;
  2308.         }
  2309.     }
  2310.  
  2311.     if (input_ui_pressed(IPT_UI_SELECT))
  2312.     {
  2313.         if (sel == 7)
  2314.         {
  2315.             /* return to main menu */
  2316.             submenu_choice = 0;
  2317.             sel = -1;
  2318.         }
  2319.         else if ((sel == 4) || (sel == 1))
  2320.         {
  2321.             /* wait for key up */
  2322.             while (input_ui_pressed(IPT_UI_SELECT)) {};
  2323.  
  2324.             /* flush the text buffer */
  2325.             osd_readkey_unicode (1);
  2326.             textedit_active ^= 1;
  2327.         }
  2328.         else
  2329.         {
  2330.             submenu_choice = 1;
  2331.             /* tell updatescreen() to clean after us */
  2332.             need_to_clear_bitmap = 1;
  2333.         }
  2334.     }
  2335.  
  2336.     /* Cancel pops us up a menu level */
  2337.     if (input_ui_pressed(IPT_UI_CANCEL))
  2338.         sel = -1;
  2339.  
  2340.     /* The UI key takes us all the way back out */
  2341.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  2342.         sel = -2;
  2343.  
  2344.     if (sel == -1 || sel == -2)
  2345.     {
  2346.         textedit_active = 0;
  2347.         /* flush the text buffer */
  2348.         osd_readkey_unicode (1);
  2349.         /* tell updatescreen() to clean after us */
  2350.         need_to_clear_bitmap = 1;
  2351.     }
  2352.  
  2353.     /* After we've weeded out any control characters, look for text */
  2354.     if (textedit_active)
  2355.     {
  2356.         int code;
  2357.  
  2358.         /* is this the address field? */
  2359.         if (sel == 1)
  2360.         {
  2361.             INT8 hex_val;
  2362.  
  2363.             /* see if a hex digit was typed */
  2364.             hex_val = code_read_hex_async();
  2365.             if (hex_val != -1)
  2366.             {
  2367.                 /* shift over one digit, add in the new value and clip */
  2368.                 watches[watchnum].address <<= 4;
  2369.                 watches[watchnum].address |= hex_val;
  2370.                 watches[watchnum].address &= cpunum_address_mask(watches[watchnum].cpu);
  2371.             }
  2372.         }
  2373.         else
  2374.         {
  2375.             int length = strlen(watches[watchnum].label);
  2376.  
  2377.             if (length < 254)
  2378.             {
  2379.                 code = osd_readkey_unicode(0) & 0xff; /* no 16-bit support */
  2380.  
  2381.                 if (code)
  2382.                 {
  2383.                     if (code == 0x08) /* backspace */
  2384.                     {
  2385.                         /* clear the buffer */
  2386.                         watches[watchnum].label[0] = 0x00;
  2387.                     }
  2388.                     else
  2389.                     {
  2390.                         /* append the character */
  2391.                         watches[watchnum].label[length] = code;
  2392.                         watches[watchnum].label[length+1] = 0x00;
  2393.                     }
  2394.                 }
  2395.             }
  2396.         }
  2397.     }
  2398.  
  2399.     return sel + 1;
  2400. }
  2401.  
  2402. INT32 ChooseWatch (struct osd_bitmap *bitmap, INT32 selected)
  2403. {
  2404.     int sel;
  2405.     static INT8 submenu_choice;
  2406.     const char *menu_item[MAX_WATCHES + 2];
  2407.     char buf[MAX_WATCHES][80];
  2408.     const char *watchpoint_str = ui_getstring (UI_watchpoint);
  2409.     const char *disabled_str = ui_getstring (UI_disabled);
  2410.     int i, total = 0;
  2411.  
  2412.  
  2413.     sel = selected - 1;
  2414.  
  2415.     /* If a submenu has been selected, go there */
  2416.     if (submenu_choice)
  2417.     {
  2418.         submenu_choice = ConfigureWatch (bitmap, submenu_choice, sel);
  2419.  
  2420.         if (submenu_choice == -1)
  2421.         {
  2422.             submenu_choice = 0;
  2423.             sel = -2;
  2424.         }
  2425.  
  2426.         return sel + 1;
  2427.     }
  2428.  
  2429.     /* No submenu active, do the watchpoint menu */
  2430.     for (i = 0; i < MAX_WATCHES; i ++)
  2431.     {
  2432.         sprintf (buf[i], "%s %d: ", watchpoint_str, i);
  2433.         /* If the watchpoint is active (1 or more bytes long), show it */
  2434.         if (watches[i].num_bytes)
  2435.         {
  2436.             char buf2[80];
  2437.  
  2438.             if (cpunum_address_bits(watches[i].cpu) <= 16)
  2439.             {
  2440.                 sprintf (buf2, "%04x", watches[i].address);
  2441.                 strcat (buf[i], buf2);
  2442.             }
  2443.             else
  2444.             {
  2445.                 sprintf (buf2, "%08x", watches[i].address);
  2446.                 strcat (buf[i], buf2);
  2447.             }
  2448.         }
  2449.         else
  2450.             strcat (buf[i], disabled_str);
  2451.  
  2452.         menu_item[total++] = buf[i];
  2453.     }
  2454.  
  2455.     menu_item[total++] = ui_getstring (UI_returntoprior);
  2456.     menu_item[total] = 0;    /* terminate array */
  2457.  
  2458.     ui_displaymenu(bitmap,menu_item,0,0,sel,0);
  2459.  
  2460.     if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
  2461.         sel = (sel + 1) % total;
  2462.  
  2463.     if (input_ui_pressed_repeat(IPT_UI_UP,8))
  2464.         sel = (sel + total - 1) % total;
  2465.  
  2466.     if (input_ui_pressed(IPT_UI_SELECT))
  2467.     {
  2468.         if (sel == MAX_WATCHES)
  2469.         {
  2470.             submenu_choice = 0;
  2471.             sel = -1;
  2472.         }
  2473.         else
  2474.         {
  2475.             submenu_choice = 1;
  2476.             /* tell updatescreen() to clean after us */
  2477.             need_to_clear_bitmap = 1;
  2478.         }
  2479.     }
  2480.  
  2481.     /* Cancel pops us up a menu level */
  2482.     if (input_ui_pressed(IPT_UI_CANCEL))
  2483.         sel = -1;
  2484.  
  2485.     /* The UI key takes us all the way back out */
  2486.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  2487.         sel = -2;
  2488.  
  2489.     if (sel == -1 || sel == -2)
  2490.     {
  2491.         /* tell updatescreen() to clean after us */
  2492.         need_to_clear_bitmap = 1;
  2493.     }
  2494.  
  2495.     return sel + 1;
  2496. }
  2497.  
  2498.  
  2499. #ifdef macintosh
  2500. #pragma mark -
  2501. #endif
  2502.  
  2503. static INT32 DisplayHelpFile (INT32 selected)
  2504. {
  2505.     return -1;
  2506. }
  2507.  
  2508. #ifdef macintosh
  2509. #pragma mark -
  2510. #endif
  2511.  
  2512. INT32 cheat_menu(struct osd_bitmap *bitmap, INT32 selected)
  2513. {
  2514. #ifdef MENU_return
  2515. #undef MENU_return
  2516. #endif
  2517. #define MENU_return 8
  2518.  
  2519.     const char *menu_item[10];
  2520.     INT32 sel;
  2521.     UINT8 total = 0;
  2522.     static INT8 submenu_choice;
  2523.  
  2524.     sel = selected - 1;
  2525.  
  2526.     /* If a submenu has been selected, go there */
  2527.     if (submenu_choice)
  2528.     {
  2529.         switch (sel)
  2530.         {
  2531.             case 0:
  2532.                 submenu_choice = EnableDisableCheatMenu (bitmap, submenu_choice);
  2533.                 break;
  2534.             case 1:
  2535.                 submenu_choice = AddEditCheatMenu (bitmap, submenu_choice);
  2536.                 break;
  2537.             case 2:
  2538.                 submenu_choice = StartSearch (submenu_choice);
  2539.                 break;
  2540.             case 3:
  2541.                 submenu_choice = ContinueSearch (submenu_choice, 0);
  2542.                 break;
  2543.             case 4:
  2544.                 submenu_choice = ContinueSearch (submenu_choice, 1);
  2545.                 break;
  2546.             case 5:
  2547.                 submenu_choice = RestoreSearch (submenu_choice);
  2548.                 break;
  2549.             case 6:
  2550.                 submenu_choice = ChooseWatch (bitmap, submenu_choice);
  2551.                 break;
  2552.             case 7:
  2553.                 submenu_choice = DisplayHelpFile (submenu_choice);
  2554.                 break;
  2555.             case MENU_return:
  2556.                 submenu_choice = 0;
  2557.                 sel = -1;
  2558.                 break;
  2559.         }
  2560.  
  2561.         if (submenu_choice == -1)
  2562.             submenu_choice = 0;
  2563.  
  2564.         return sel + 1;
  2565.     }
  2566.  
  2567.     /* No submenu active, display the main cheat menu */
  2568.     menu_item[total++] = ui_getstring (UI_enablecheat);
  2569.     menu_item[total++] = ui_getstring (UI_addeditcheat);
  2570.     menu_item[total++] = ui_getstring (UI_startcheat);
  2571.     menu_item[total++] = ui_getstring (UI_continuesearch);
  2572.     menu_item[total++] = ui_getstring (UI_viewresults);
  2573.     menu_item[total++] = ui_getstring (UI_restoreresults);
  2574.     menu_item[total++] = ui_getstring (UI_memorywatch);
  2575.     menu_item[total++] = ui_getstring (UI_generalhelp);
  2576.     menu_item[total++] = ui_getstring (UI_returntomain);
  2577.     menu_item[total] = 0;
  2578.  
  2579.     ui_displaymenu(bitmap,menu_item,0,0,sel,0);
  2580.  
  2581.     if (input_ui_pressed_repeat(IPT_UI_DOWN,8))
  2582.         sel = (sel + 1) % total;
  2583.  
  2584.     if (input_ui_pressed_repeat(IPT_UI_UP,8))
  2585.         sel = (sel + total - 1) % total;
  2586.  
  2587.     if (input_ui_pressed(IPT_UI_SELECT))
  2588.     {
  2589.         if (sel == MENU_return)
  2590.         {
  2591.             submenu_choice = 0;
  2592.             sel = -1;
  2593.         }
  2594.         else
  2595.         {
  2596.             submenu_choice = 1;
  2597.             /* tell updatescreen() to clean after us */
  2598.             need_to_clear_bitmap = 1;
  2599.         }
  2600.     }
  2601.  
  2602.     /* Cancel pops us up a menu level */
  2603.     if (input_ui_pressed(IPT_UI_CANCEL))
  2604.         sel = -1;
  2605.  
  2606.     /* The UI key takes us all the way back out */
  2607.     if (input_ui_pressed(IPT_UI_CONFIGURE))
  2608.         sel = -2;
  2609.  
  2610.     if (sel == -1 || sel == -2)
  2611.     {
  2612.         /* tell updatescreen() to clean after us */
  2613.         need_to_clear_bitmap = 1;
  2614.     }
  2615.  
  2616.     return sel + 1;
  2617. }
  2618.  
  2619. /* Free allocated arrays */
  2620. void StopCheat(void)
  2621. {
  2622.     int i;
  2623.  
  2624.     for (i = 0; i < LoadedCheatTotal; i ++)
  2625.     {
  2626.         /* free storage for the strings */
  2627.         if (CheatTable[i].name)
  2628.         {
  2629.             free (CheatTable[i].name);
  2630.             CheatTable[i].name = NULL;
  2631.         }
  2632.         if (CheatTable[i].comment)
  2633.         {
  2634.             free (CheatTable[i].comment);
  2635.             CheatTable[i].comment = NULL;
  2636.         }
  2637.     }
  2638.  
  2639. #if 0
  2640.   reset_table (StartRam);
  2641.   reset_table (BackupRam);
  2642.   reset_table (FlagTable);
  2643.  
  2644.   reset_table (OldBackupRam);
  2645.   reset_table (OldFlagTable);
  2646. #endif
  2647. }
  2648.  
  2649. void DoCheat(struct osd_bitmap *bitmap)
  2650. {
  2651.     DisplayWatches (bitmap);
  2652.  
  2653.     if ((CheatEnabled) && (ActiveCheatTotal))
  2654.     {
  2655.         int i, j;
  2656.  
  2657.         /* At least one cheat is active, handle them */
  2658.         for (i = 0; i < LoadedCheatTotal; i ++)
  2659.         {
  2660.             /* skip if this isn't an active cheat */
  2661.             if ((CheatTable[i].flags & CHEAT_FLAG_ACTIVE) == 0) continue;
  2662.  
  2663.             /* loop through all subcheats */
  2664.             for (j = 0; j <= CheatTable[i].num_sub; j ++)
  2665.             {
  2666.                 struct subcheat_struct *subcheat = &CheatTable[i].subcheat[j];
  2667.  
  2668.                 if (subcheat->flags & SUBCHEAT_FLAG_DONE) continue;
  2669.  
  2670.                 /* most common case: 0 */
  2671.                 if (subcheat->code == kCheatSpecial_Poke)
  2672.                 {
  2673.                     WRITE_CHEAT;
  2674.                 }
  2675.                 /* Check special function if cheat counter is ready */
  2676.                 else if (subcheat->frame_count == 0)
  2677.                 {
  2678.                     switch (subcheat->code)
  2679.                     {
  2680.                         case 1:
  2681.                             WRITE_CHEAT;
  2682.                             subcheat->flags |= SUBCHEAT_FLAG_DONE;
  2683.                             break;
  2684.                         case 2:
  2685.                         case 3:
  2686.                         case 4:
  2687.                             WRITE_CHEAT;
  2688.                             subcheat->frame_count = subcheat->frames_til_trigger;
  2689.                             break;
  2690.  
  2691.                         /* 5,6,7 check if the value has changed, if yes, start a timer. */
  2692.                         /* When the timer ends, change the location */
  2693.                         case 5:
  2694.                         case 6:
  2695.                         case 7:
  2696.                             if (subcheat->flags & SUBCHEAT_FLAG_TIMED)
  2697.                             {
  2698.                                 WRITE_CHEAT;
  2699.                                 subcheat->flags &= ~SUBCHEAT_FLAG_TIMED;
  2700.                             }
  2701.                             else if (COMPARE_CHEAT)
  2702.                             {
  2703.                                 subcheat->frame_count = subcheat->frames_til_trigger;
  2704.                                 subcheat->flags |= SUBCHEAT_FLAG_TIMED;
  2705.                             }
  2706.                             break;
  2707.  
  2708.                         /* 8,9,10,11 do not change the location if the value change by X every frames
  2709.                           This is to try to not change the value of an energy bar
  2710.                            when a bonus is awarded to it at the end of a level
  2711.                            See Kung Fu Master */
  2712.                         case 8:
  2713.                         case 9:
  2714.                         case 10:
  2715.                         case 11:
  2716.                             if (subcheat->flags & SUBCHEAT_FLAG_TIMED)
  2717.                             {
  2718.                                 /* Check the value to see if it has increased over the original value by 1 or more */
  2719.                                 if (READ_CHEAT != subcheat->backup - (kCheatSpecial_Backup1 - subcheat->code + 1))
  2720.                                     WRITE_CHEAT;
  2721.                                 subcheat->flags &= ~SUBCHEAT_FLAG_TIMED;
  2722.                             }
  2723.                             else
  2724.                             {
  2725.                                 subcheat->backup = READ_CHEAT;
  2726.                                 subcheat->frame_count = 1;
  2727.                                 subcheat->flags |= SUBCHEAT_FLAG_TIMED;
  2728.                             }
  2729.                             break;
  2730.  
  2731.                         /* 20-24: set bits */
  2732.                         case 20:
  2733.                             computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT | subcheat->data);
  2734.                             break;
  2735.                         case 21:
  2736.                             computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT | subcheat->data);
  2737.                             subcheat->flags |= SUBCHEAT_FLAG_DONE;
  2738.                             break;
  2739.                         case 22:
  2740.                         case 23:
  2741.                         case 24:
  2742.                             computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT | subcheat->data);
  2743.                             subcheat->frame_count = subcheat->frames_til_trigger;
  2744.                             break;
  2745.  
  2746.                         /* 40-44: reset bits */
  2747.                         case 40:
  2748.                             computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT & ~subcheat->data);
  2749.                             break;
  2750.                         case 41:
  2751.                             computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT & ~subcheat->data);
  2752.                             subcheat->flags |= SUBCHEAT_FLAG_DONE;
  2753.                             break;
  2754.                         case 42:
  2755.                         case 43:
  2756.                         case 44:
  2757.                             computer_writemem_byte (subcheat->cpu, subcheat->address, READ_CHEAT & ~subcheat->data);
  2758.                             subcheat->frame_count = subcheat->frames_til_trigger;
  2759.                             break;
  2760.  
  2761.                         /* 60-65: user select, poke when changes */
  2762.                         case 60: case 61: case 62: case 63: case 64: case 65:
  2763.                             if (subcheat->flags & SUBCHEAT_FLAG_TIMED)
  2764.                             {
  2765.                                 if (READ_CHEAT != subcheat->backup)
  2766.                                 {
  2767.                                     WRITE_CHEAT;
  2768.                                     subcheat->flags |= SUBCHEAT_FLAG_DONE;
  2769.                                 }
  2770.                             }
  2771.                             else
  2772.                             {
  2773.                                 subcheat->backup = READ_CHEAT;
  2774.                                 subcheat->frame_count = 1;
  2775.                                 subcheat->flags |= SUBCHEAT_FLAG_TIMED;
  2776.                             }
  2777.                             break;
  2778.  
  2779.                         /* 70-75: user select, poke once */
  2780.                         case 70: case 71: case 72: case 73: case 74: case 75:
  2781.                             WRITE_CHEAT;
  2782.                             subcheat->flags |= SUBCHEAT_FLAG_DONE;
  2783.                         break;
  2784.                     }
  2785.                 }
  2786.                 else
  2787.                 {
  2788.                     subcheat->frame_count--;
  2789.                 }
  2790.             }
  2791.         } /* end for */
  2792.     }
  2793.  
  2794.     /* IPT_UI_TOGGLE_CHEAT Enable/Disable the active cheats on the fly. Required for some cheats. */
  2795.     if (input_ui_pressed(IPT_UI_TOGGLE_CHEAT))
  2796.     {
  2797.         /* Hold down shift to toggle the watchpoints */
  2798.         if (code_pressed(KEYCODE_LSHIFT) || code_pressed(KEYCODE_RSHIFT))
  2799.         {
  2800.             is_watch_visible ^= 1;
  2801.             usrintf_showmessage("%s %s", ui_getstring (UI_watchpoints), (is_watch_visible ? ui_getstring (UI_on) : ui_getstring (UI_off)));
  2802.         }
  2803.         else if (ActiveCheatTotal)
  2804.         {
  2805.             CheatEnabled ^= 1;
  2806.             usrintf_showmessage("%s %s", ui_getstring (UI_cheats), (CheatEnabled ? ui_getstring (UI_on) : ui_getstring (UI_off)));
  2807.         }
  2808.     }
  2809.  
  2810. #if 0
  2811.   /* KEYCODE_END loads the "Continue Search" sub-menu of the cheat engine */
  2812.   if ( keyboard_pressed_memory( KEYCODE_END ) )
  2813.   {
  2814.     osd_sound_enable(0);
  2815.     osd_pause(1);
  2816.     ContinueSearch(0, 0);
  2817.     osd_pause(0);
  2818.     osd_sound_enable(1);
  2819.   }
  2820. #endif
  2821.  
  2822. }
  2823.